vue 文本中的\n 、<br>换行显示

一、背景: 后端接口返回数据以\n 作为换行符,前端显示时候需要换行显示;

demo:

 <p style="white-space: pre-wrap;">{{ info }}</p>
 data() {
   return {
     info: '1、优化图片\n  2、   优化时间\n'
   }
 },

项目上:

效果:

接口数据直接获取:

<template>
    <div style="white-space: pre-wrap;">{{logDataInfo}}
        </div>
      </div>
</tempalte>

<script lang="ts">
methods: {

loadMore(){
try {
        const response = await API.Defect.logDetailsData({
          page: this.currentPage,
          pageSize: this.pageSize,
          fileId: id
        })
        this.logTotal = response.data.total
        const data = response.data.list
        if (data) {
          this.logDataInfo = data
         
        } 
      } catch (error) {
        warn(error, true)
      }

}

}

</script>

注意: style中white-sapce: pre-wrap; 一定要添加;

white-space学习

接口数据res.data.list :

"<template>\n  <div class=\"graph-container\">\n    <PageHeader title=\"覆盖率图谱\">\n      <template slot=\"button-items\">\n        <SearchInputVue :keyword.sync=\"keyword\" @trigger-event=\"getInitGraphData(1)\" placeholder=\"输入类名过滤\" />\n      </template>\n    </PageHeader>\n    <div id=\"relationGraphDiv\" style=\"height: calc(100vh - 160px)\">\n      <RelationGraph ref=\"seeksRelationGraph\" :options=\"graphOptions\">\n        <template slot=\"node\" slot-scope=\"{ node }\">\n          <div :class=\"`node-container node-type-${node.data.category}`\" @click=\"nodeClick(node.data)\">\n            <div v-if=\"node.data.category !== 0\" class=\"node-title\">\n              <div v-if=\"node.data.category === 2\" class=\"node-title-top\">\n                {{ node.data.name }}\n                <span v-if=\"node.data.path\" :title=\"node.data.path\" style=\"font-size: 12px\">({{ node.data.path }})</span>\n              </div>\n              <div v-if=\"node.data.category !== 2\">{{ node.data.name }}</div>\n              <div v-if=\"node.data.category === 2\" :title=\"node.data.params\" style=\"font-size: 12px\">{{ node.data.params }}</div>\n            </div>\n            <div v-if=\"node.data.category !== 0\" class=\"node-info\">\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">行覆盖率</div>\n                <div :class=\"`level-${node.data.linesLevel}`\">{{ node.data.lines }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">分支覆盖率</div>\n                <div :class=\"`level-${node.data.branchesLevel}`\">{{ node.data.branches }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">函数覆盖率</div>\n                <div :class=\"`level-${node.data.functionsLevel}`\">{{ node.data.functions }}%</div>\n              </div>\n            </div>\n            <div v-if=\"node.data.category === 0\" class=\"node-begin\">{{ node.data.name }}</div>\n          </div>\n        </template>\n      </RelationGraph>\n    </div>\n  </div>\n</template>\n<script lang=\"ts\">\nimport Vue from 'vue'\nimport { mapGetters } from 'vuex'\nimport RelationGraph from 'relation-graph'\nimport { Loading } from 'element-ui'\n\nimport API from '@/api'\nimport { warn } from '@/utils/common'\n// import AnbanButtonVue from '@/components/Button/AnbanButton.vue'\nimport SearchInputVue from '@/components/Input/SearchInput.vue'\n\nimport PageHeader from '@/components/pageHeader/index.vue'\n\nexport default Vue.extend({\n  name: 'CoverageGraph',\n  components: {\n    PageHeader,\n    SearchInputVue,\n    RelationGraph\n  },\n  data() {\n    return {\n      rawData: {\n        nodes: [],\n        links: []\n      },\n      renderData: {\n        nodes: [] as any[],\n        links: [] as { from: string; to: string; text?: string }[]\n      },\n      unLoadExpandNodes: [] as string[],\n      height: document.body.clientHeight - 124,\n      graphOptions: {\n        layouts: [\n          {\n            label: '布局',\n            layoutName: 'tree',\n            layoutClassName: 'seeks-layout-center',\n            from: 'left',\n            defaultNodeShape: 2,\n            distance_coefficient: 1,\n            defaultLineShape: 4,\n            defaultNodeBorderWidth: 0,\n            defaultLineColor: '#cccccc',\n            defaultNodeColor: '#43a2f1',\n            min_per_width: '400',\n            min_per_height: '300'\n          }\n        ],\n        defaultExpandHolderPosition: 'right',\n        zoomToFitWhenRefresh: false,\n        moveToCenterWhenRefresh: true\n      },\n      keyword: ''\n    }\n  },\n  computed: {\n    ...mapGetters(['currentModuleInfo', 'currentInstanceInfo'])\n  },\n  mounted() {\n    if (this.$route.query.path) {\n      this.keyword = decodeURIComponent(this.$route.query.path as string)\n    }\n    this.getInitGraphData(0)\n  },\n  methods: {\n    /**\n     * 获得init数据(api)\n     */\n    async getInitGraphData(type: number) {\n      if (type === 1 && !this.keyword.trim()) {\n        this.renderData.nodes = this.rawData.nodes\n        this.renderData.links = this.rawData.links\n        this.renderGraphData()\n        return\n      }\n      const loadingInstance = Loading.service({\n        target: '#relationGraphDiv',\n        text: '数据加载中'\n      })\n      try {\n        const { data } = await API.Instance.getCoverageGraphRootData({\n          instanceId: this.currentInstanceInfo.id,\n          name: this.keyword,\n          id: ''\n        })\n        setTimeout(() => loadingInstance.close(), 500)\n        if (!data.length) {\n          if (type === 0) {\n            this.$message.warning('暂无覆盖率图谱数据')\n          } else {\n            this.$message.warning(`暂无 ${this.keyword} 相关类名`)\n          }\n          return\n        }\n        const initNode = {\n          id: 'initId',\n          data: {\n            name: this.currentModuleInfo.projectName,\n            category: 0\n          }\n        }\n        this.mergeOriginalData(type, data, initNode)\n        this.renderGraphData()\n      } catch (error) {\n        warn(error, true)\n        loadingInstance.close()\n      }\n    },\n    mergeOriginalData(type: number, data: any[], rootNode: any) {\n      const links = []\n      const unLoadExpandNodes: string[] = []\n      const apiNodes = data.reduce((merge, item) => {\n        const parentId = `id_${item.name}_${new Date().getTime()}`\n        const parentNode = {\n          id: parentId,\n          data: {\n            id: parentId,\n            name: item.name,\n            category: 1,\n            branches: item.branches === 'NaN' || !item.branches ? 0 : item.branches.toFixed(2),\n            branchesLevel: this.coverageLevel(item.branches),\n            functions: item.functions === 'NaN' || !item.functions ? 0 : item.functions.toFixed(2),\n            functionsLevel: this.coverageLevel(item.functions),\n            lines: item.lines === 'NaN' || !item.lines ? 0 : item.lines.toFixed(2),\n            linesLevel: this.coverageLevel(item.lines)\n          }\n        }\n        const parentLink = {\n          from: rootNode.id,\n          to: parentId,\n          text: rootNode.id === 'initId' ? `exec: ${item.execute_count || 0}` : '',\n          useTextPath: true\n        }\n        merge.push(parentNode)\n        links.push(parentLink)\n        if (item.methods && item.methods.length) {\n          item.methods.forEach(method => {\n            const childId = `id_${method.name}_${method.path}_${new Date().getTime()}`\n            unLoadExpandNodes.push(childId)\n            const child = {\n              id: childId,\n              data: {\n                id: childId,\n                className: item.name,\n                name: method.name,\n                path: method.path,\n                category: 2,\n                params: method.params,\n                branches: method.branches === 'NaN' || !method.branches ? 0 : method.branches.toFixed(2),\n                branchesLevel: this.coverageLevel(method.branches),\n                functions: method.functions === 'NaN' || !method.functions ? 0 : method.functions.toFixed(2),\n                functionsLevel: this.coverageLevel(method.functions),\n                lines: method.lines === 'NaN' || !method.lines ? 0 : method.lines.toFixed(2),\n                linesLevel: this.coverageLevel(method.lines)\n              }\n            }\n            const link = {\n              from: parentId,\n              to: childId\n              // text: `exec: ${method.execute_count || 0}`,\n              // useTextPath: true\n            }\n            merge.push(child)\n            links.push(link)\n          })\n        }\n        return merge\n      }, [])\n      const nodes = type === 0 || type === 1 ? [rootNode, ...apiNodes] : apiNodes\n      if (type === 0) {\n        // 初始化\n        this.rawData.nodes = nodes\n        this.rawData.links = links\n        this.renderData.nodes = nodes\n        this.renderData.links = links\n        this.unLoadExpandNodes = unLoadExpandNodes\n      } else if (type === 1) {\n        // 过滤\n        this.renderData.nodes = nodes\n        this.renderData.links = links\n        this.unLoadExpandNodes = unLoadExpandNodes\n      } else if (type === 2) {\n        // 增加\n        this.rawData.nodes = [...this.rawData.nodes, ...nodes]\n        this.rawData.links = [...this.rawData.links, ...links]\n        this.unLoadExpandNodes = [...this.unLoadExpandNodes, ...unLoadExpandNodes]\n        this.addGraphData(nodes, links)\n      }\n    },\n    coverageLevel(rate: number) {\n      if (typeof rate !== 'number') return 0\n      return rate === 0 ? 0 : rate < 60 ? 1 : rate < 90 ? 2 : 3\n    },\n    renderGraphData() {\n      const __graph_json_data = {\n        rootId: 'initId',\n        nodes: this.renderData.nodes,\n        lines: this.renderData.links\n      }\n      console.log(__graph_json_data)\n      this.$refs.seeksRelationGraph.setJsonData(__graph_json_data)\n      this.$refs.seeksRelationGraph.refresh()\n    },\n    addGraphData(nodes, links) {\n      const __graph_json_data = {\n        rootId: 'initId',\n        nodes,\n        links\n      }\n      this.$refs.seeksRelationGraph.appendJsonData(__graph_json_data)\n    },\n    async nodeClick(nodeData: any) {\n      console.log(nodeData)\n      if (this.unLoadExpandNodes.includes(nodeData.id)) {\n        // 未加载过子路径\n        await this.getExpandData(nodeData.id, nodeData.className, nodeData.name, nodeData.params)\n      }\n    },\n    /**\n     * 增加子节点\n     */\n    async getExpandData(id: string, className: string, methodName: string, params: any) {\n      if (!this.unLoadExpandNodes.includes(id)) return\n      const loadingInstance = Loading.service({\n        target: '#relationGraphDiv',\n        text: '数据加载中'\n      })\n      try {\n        const { data } = await API.Instance.getCoverageGrapChildhData({\n          instanceId: this.currentInstanceInfo.id,\n          className,\n          methodName,\n          params: encodeURIComponent(params)\n        })\n        setTimeout(() => loadingInstance.close(), 500)\n        if (data.length) {\n          this.mergeOriginalData(2, data, { id })\n        }\n        this.unLoadExpandNodes = this.unLoadExpandNodes.filter(nodeId => nodeId !== id)\n      } catch (error) {\n        warn(error, true)\n        loadingInstance.close()\n      }\n    }\n  }\n})\n</script>\n<style lang=\"stylus\" Scope>\n.node-container {\n  width: 240px;\n  height: 105px;\n  box-sizing: border-box;\n  background: #3F51B5;\n  border-radius: 4px;\n  background-color: #484750;\n  overflow: hidden;\n  &.node-type-0 {\n    width: auto;\n    padding: 0 32px;\n    line-height: 105px;\n    font-size: 20px;\n    font-weight: 700;\n  }\n  &.node-type-1 {\n    .node-title {\n      height: 57px;\n      background: #387dff;\n      color: #fff;\n      word-break: break-all;\n      white-space: unset;\n      line-height: 18px;\n    }\n  }\n  .node-title-top {\n    padding-bottom: 4px;\n    border-bottom: 1px solid #484750;\n    margin-bottom: 4px;\n  }\n  .node-title {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    background-color: #aabee3;\n    padding: 8px 12px;\n    color: #232529;\n    text-align: left;\n  }\n  .node-info {\n    display: flex;\n    font-size: 12px;\n    justify-content: space-between;\n    padding: 8px;\n    .node-info-name {\n      margin-bottom: 4px;\n    }\n    .level-1 {\n      color: #FF4455;\n    }\n    .level-2 {\n      color: #FE7C4B;\n    }\n    .level-3 {\n      color: #49C721;\n    }\n    .level-0 {\n      color: #aabee3;\n    }\n  }\n}\n</style>\n<style lang=\"stylus\">\n.c-current-zoom {\n  color: #999999 !important;\n}\n.relation-graph .rel-map {\n  background-color: #1a1919 !important;\n}\n.relation-graph .rel-toolbar .c-mb-button:hover {\n  background-color: rgba(153, 153, 153, 0.5) !important;\n}\n.relation-graph .rel-node-checked {\n  width: 100% !important;\n  box-shadow: 0 0px 5px 2px #2196F3 !important;\n}\n.el-loading-mask {\n  background-color: rgba(34, 34, 34, 0.8) !important;\n}\n</style>\n<template>\n  <div class=\"graph-container\">\n    <PageHeader title=\"覆盖率图谱\">\n      <template slot=\"button-items\">\n        <SearchInputVue :keyword.sync=\"keyword\" @trigger-event=\"getInitGraphData(1)\" placeholder=\"输入类名过滤\" />\n      </template>\n    </PageHeader>\n    <div id=\"relationGraphDiv\" style=\"height: calc(100vh - 160px)\">\n      <RelationGraph ref=\"seeksRelationGraph\" :options=\"graphOptions\">\n        <template slot=\"node\" slot-scope=\"{ node }\">\n          <div :class=\"`node-container node-type-${node.data.category}`\" @click=\"nodeClick(node.data)\">\n            <div v-if=\"node.data.category !== 0\" class=\"node-title\">\n              <div v-if=\"node.data.category === 2\" class=\"node-title-top\">\n                {{ node.data.name }}\n                <span v-if=\"node.data.path\" :title=\"node.data.path\" style=\"font-size: 12px\">({{ node.data.path }})</span>\n              </div>\n              <div v-if=\"node.data.category !== 2\">{{ node.data.name }}</div>\n              <div v-if=\"node.data.category === 2\" :title=\"node.data.params\" style=\"font-size: 12px\">{{ node.data.params }}</div>\n            </div>\n            <div v-if=\"node.data.category !== 0\" class=\"node-info\">\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">行覆盖率</div>\n                <div :class=\"`level-${node.data.linesLevel}`\">{{ node.data.lines }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">分支覆盖率</div>\n                <div :class=\"`level-${node.data.branchesLevel}`\">{{ node.data.branches }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">函数覆盖率</div>\n                <div :class=\"`level-${node.data.functionsLevel}`\">{{ node.data.functions }}%</div>\n              </div>\n            </div>\n            <div v-if=\"node.data.category === 0\" class=\"node-begin\">{{ node.data.name }}</div>\n          </div>\n        </template>\n      </RelationGraph>\n    </div>\n  </div>\n</template>\n<script lang=\"ts\">\nimport Vue from 'vue'\nimport { mapGetters } from 'vuex'\nimport RelationGraph from 'relation-graph'\nimport { Loading } from 'element-ui'\n\nimport API from '@/api'\nimport { warn } from '@/utils/common'\n// import AnbanButtonVue from '@/components/Button/AnbanButton.vue'\nimport SearchInputVue from '@/components/Input/SearchInput.vue'\n\nimport PageHeader from '@/components/pageHeader/index.vue'\n\nexport default Vue.extend({\n  name: 'CoverageGraph',\n  components: {\n    PageHeader,\n    SearchInputVue,\n    RelationGraph\n  },\n  data() {\n    return {\n      rawData: {\n        nodes: [],\n        links: []\n      },\n      renderData: {\n        nodes: [] as any[],\n        links: [] as { from: string; to: string; text?: string }[]\n      },\n      unLoadExpandNodes: [] as string[],\n      height: document.body.clientHeight - 124,\n      graphOptions: {\n        layouts: [\n          {\n            label: '布局',\n            layoutName: 'tree',\n            layoutClassName: 'seeks-layout-center',\n            from: 'left',\n            defaultNodeShape: 2,\n            distance_coefficient: 1,\n            defaultLineShape: 4,\n            defaultNodeBorderWidth: 0,\n            defaultLineColor: '#cccccc',\n            defaultNodeColor: '#43a2f1',\n            min_per_width: '400',\n            min_per_height: '300'\n          }\n        ],\n        defaultExpandHolderPosition: 'right',\n        zoomToFitWhenRefresh: false,\n        moveToCenterWhenRefresh: true\n      },\n      keyword: ''\n    }\n  },\n  computed: {\n    ...mapGetters(['currentModuleInfo', 'currentInstanceInfo'])\n  },\n  mounted() {\n    if (this.$route.query.path) {\n      this.keyword = decodeURIComponent(this.$route.query.path as string)\n    }\n    this.getInitGraphData(0)\n  },\n  methods: {\n    /**\n     * 获得init数据(api)\n     */\n    async getInitGraphData(type: number) {\n      if (type === 1 && !this.keyword.trim()) {\n        this.renderData.nodes = this.rawData.nodes\n        this.renderData.links = this.rawData.links\n        this.renderGraphData()\n        return\n      }\n      const loadingInstance = Loading.service({\n        target: '#relationGraphDiv',\n        text: '数据加载中'\n      })\n      try {\n        const { data } = await API.Instance.getCoverageGraphRootData({\n          instanceId: this.currentInstanceInfo.id,\n          name: this.keyword,\n          id: ''\n        })\n        setTimeout(() => loadingInstance.close(), 500)\n        if (!data.length) {\n          if (type === 0) {\n            this.$message.warning('暂无覆盖率图谱数据')\n          } else {\n            this.$message.warning(`暂无 ${this.keyword} 相关类名`)\n          }\n          return\n        }\n        const initNode = {\n          id: 'initId',\n          data: {\n            name: this.currentModuleInfo.projectName,\n            category: 0\n          }\n        }\n        this.mergeOriginalData(type, data, initNode)\n        this.renderGraphData()\n      } catch (error) {\n        warn(error, true)\n        loadingInstance.close()\n      }\n    },\n    mergeOriginalData(type: number, data: any[], rootNode: any) {\n      const links = []\n      const unLoadExpandNodes: string[] = []\n      const apiNodes = data.reduce((merge, item) => {\n        const parentId = `id_${item.name}_${new Date().getTime()}`\n        const parentNode = {\n          id: parentId,\n          data: {\n            id: parentId,\n            name: item.name,\n            category: 1,\n            branches: item.branches === 'NaN' || !item.branches ? 0 : item.branches.toFixed(2),\n            branchesLevel: this.coverageLevel(item.branches),\n            functions: item.functions === 'NaN' || !item.functions ? 0 : item.functions.toFixed(2),\n            functionsLevel: this.coverageLevel(item.functions),\n            lines: item.lines === 'NaN' || !item.lines ? 0 : item.lines.toFixed(2),\n            linesLevel: this.coverageLevel(item.lines)\n          }\n        }\n        const parentLink = {\n          from: rootNode.id,\n          to: parentId,\n          text: rootNode.id === 'initId' ? `exec: ${item.execute_count || 0}` : '',\n          useTextPath: true\n        }\n        merge.push(parentNode)\n        links.push(parentLink)\n        if (item.methods && item.methods.length) {\n          item.methods.forEach(method => {\n            const childId = `id_${method.name}_${method.path}_${new Date().getTime()}`\n            unLoadExpandNodes.push(childId)\n            const child = {\n              id: childId,\n              data: {\n                id: childId,\n                className: item.name,\n                name: method.name,\n                path: method.path,\n                category: 2,\n                params: method.params,\n                branches: method.branches === 'NaN' || !method.branches ? 0 : method.branches.toFixed(2),\n                branchesLevel: this.coverageLevel(method.branches),\n                functions: method.functions === 'NaN' || !method.functions ? 0 : method.functions.toFixed(2),\n                functionsLevel: this.coverageLevel(method.functions),\n                lines: method.lines === 'NaN' || !method.lines ? 0 : method.lines.toFixed(2),\n                linesLevel: this.coverageLevel(method.lines)\n              }\n            }\n            const link = {\n              from: parentId,\n              to: childId\n              // text: `exec: ${method.execute_count || 0}`,\n              // useTextPath: true\n            }\n            merge.push(child)\n            links.push(link)\n          })\n        }\n        return merge\n      }, [])\n      const nodes = type === 0 || type === 1 ? [rootNode, ...apiNodes] : apiNodes\n      if (type === 0) {\n        // 初始化\n        this.rawData.nodes = nodes\n        this.rawData.links = links\n        this.renderData.nodes = nodes\n        this.renderData.links = links\n        this.unLoadExpandNodes = unLoadExpandNodes\n      } else if (type === 1) {\n        // 过滤\n        this.renderData.nodes = nodes\n        this.renderData.links = links\n        this.unLoadExpandNodes = unLoadExpandNodes\n      } else if (type === 2) {\n        // 增加\n        this.rawData.nodes = [...this.rawData.nodes, ...nodes]\n        this.rawData.links = [...this.rawData.links, ...links]\n        this.unLoadExpandNodes = [...this.unLoadExpandNodes, ...unLoadExpandNodes]\n        this.addGraphData(nodes, links)\n      }\n    },\n    coverageLevel(rate: number) {\n      if (typeof rate !== 'number') return 0\n      return rate === 0 ? 0 : rate < 60 ? 1 : rate < 90 ? 2 : 3\n    },\n    renderGraphData() {\n      const __graph_json_data = {\n        rootId: 'initId',\n        nodes: this.renderData.nodes,\n        lines: this.renderData.links\n      }\n      console.log(__graph_json_data)\n      this.$refs.seeksRelationGraph.setJsonData(__graph_json_data)\n      this.$refs.seeksRelationGraph.refresh()\n    },\n    addGraphData(nodes, links) {\n      const __graph_json_data = {\n        rootId: 'initId',\n        nodes,\n        links\n      }\n      this.$refs.seeksRelationGraph.appendJsonData(__graph_json_data)\n    },\n    async nodeClick(nodeData: any) {\n      console.log(nodeData)\n      if (this.unLoadExpandNodes.includes(nodeData.id)) {\n        // 未加载过子路径\n        await this.getExpandData(nodeData.id, nodeData.className, nodeData.name, nodeData.params)\n      }\n    },\n    /**\n     * 增加子节点\n     */\n    async getExpandData(id: string, className: string, methodName: string, params: any) {\n      if (!this.unLoadExpandNodes.includes(id)) return\n      const loadingInstance = Loading.service({\n        target: '#relationGraphDiv',\n        text: '数据加载中'\n      })\n      try {\n        const { data } = await API.Instance.getCoverageGrapChildhData({\n          instanceId: this.currentInstanceInfo.id,\n          className,\n          methodName,\n          params: encodeURIComponent(params)\n        })\n        setTimeout(() => loadingInstance.close(), 500)\n        if (data.length) {\n          this.mergeOriginalData(2, data, { id })\n        }\n        this.unLoadExpandNodes = this.unLoadExpandNodes.filter(nodeId => nodeId !== id)\n      } catch (error) {\n        warn(error, true)\n        loadingInstance.close()\n      }\n    }\n  }\n})\n</script>\n<style lang=\"stylus\" Scope>\n.node-container {\n  width: 240px;\n  height: 105px;\n  box-sizing: border-box;\n  background: #3F51B5;\n  border-radius: 4px;\n  background-color: #484750;\n  overflow: hidden;\n  &.node-type-0 {\n    width: auto;\n    padding: 0 32px;\n    line-height: 105px;\n    font-size: 20px;\n    font-weight: 700;\n  }\n  &.node-type-1 {\n    .node-title {\n      height: 57px;\n      background: #387dff;\n      color: #fff;\n      word-break: break-all;\n      white-space: unset;\n      line-height: 18px;\n    }\n  }\n  .node-title-top {\n    padding-bottom: 4px;\n    border-bottom: 1px solid #484750;\n    margin-bottom: 4px;\n  }\n  .node-title {\n    overflow: hidden;\n    text-overflow: ellipsis;\n    white-space: nowrap;\n    background-color: #aabee3;\n    padding: 8px 12px;\n    color: #232529;\n    text-align: left;\n  }\n  .node-info {\n    display: flex;\n    font-size: 12px;\n    justify-content: space-between;\n    padding: 8px;\n    .node-info-name {\n      margin-bottom: 4px;\n    }\n    .level-1 {\n      color: #FF4455;\n    }\n    .level-2 {\n      color: #FE7C4B;\n    }\n    .level-3 {\n      color: #49C721;\n    }\n    .level-0 {\n      color: #aabee3;\n    }\n  }\n}\n</style>\n<style lang=\"stylus\">\n.c-current-zoom {\n  color: #999999 !important;\n}\n.relation-graph .rel-map {\n  background-color: #1a1919 !important;\n}\n.relation-graph .rel-toolbar .c-mb-button:hover {\n  background-color: rgba(153, 153, 153, 0.5) !important;\n}\n.relation-graph .rel-node-checked {\n  width: 100% !important;\n  box-shadow: 0 0px 5px 2px #2196F3 !important;\n}\n.el-loading-mask {\n  background-color: rgba(34, 34, 34, 0.8) !important;\n}\n</style>\n<template>\n  <div class=\"graph-container\">\n    <PageHeader title=\"覆盖率图谱\">\n      <template slot=\"button-items\">\n        <SearchInputVue :keyword.sync=\"keyword\" @trigger-event=\"getInitGraphData(1)\" placeholder=\"输入类名过滤\" />\n      </template>\n    </PageHeader>\n    <div id=\"relationGraphDiv\" style=\"height: calc(100vh - 160px)\">\n      <RelationGraph ref=\"seeksRelationGraph\" :options=\"graphOptions\">\n        <template slot=\"node\" slot-scope=\"{ node }\">\n          <div :class=\"`node-container node-type-${node.data.category}`\" @click=\"nodeClick(node.data)\">\n            <div v-if=\"node.data.category !== 0\" class=\"node-title\">\n              <div v-if=\"node.data.category === 2\" class=\"node-title-top\">\n                {{ node.data.name }}\n                <span v-if=\"node.data.path\" :title=\"node.data.path\" style=\"font-size: 12px\">({{ node.data.path }})</span>\n              </div>\n              <div v-if=\"node.data.category !== 2\">{{ node.data.name }}</div>\n              <div v-if=\"node.data.category === 2\" :title=\"node.data.params\" style=\"font-size: 12px\">{{ node.data.params }}</div>\n            </div>\n            <div v-if=\"node.data.category !== 0\" class=\"node-info\">\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">行覆盖率</div>\n                <div :class=\"`level-${node.data.linesLevel}`\">{{ node.data.lines }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">分支覆盖率</div>\n                <div :class=\"`level-${node.data.branchesLevel}`\">{{ node.data.branches }}%</div>\n              </div>\n              <div class=\"node-info-item\">\n                <div class=\"node-info-name\">函数覆盖率</div>\n                <div :class=\"`level-${node.data.functionsLevel}`\">{{ node.data.functions }}%</div>\n              </div>\n            </div>\n            <div v-if=\"node.data.category === 0\" class=\"node-begin\">{{ node.data.name }}</div>\n          </div>\n        </template>\n      </RelationGraph>\n    </div>\n  </div>\n</template>\n<script lang=\"ts\">\nimport Vue from 'vue'\nimport { mapGetters } from 'vuex'\nimport RelationGraph from 'relation-graph'\nimport { Loading } from 'element-ui'\n\nimport API from '@/api'\nimport { warn } from '@/utils/common'\n// import AnbanButtonVue from '@/components/Button/AnbanButton.vue'\nimport SearchInputVue from '@/components/Input/SearchInput.vue'\n\nimport PageHeader from '@/components/pageHeader/index.vue'\n\nexport default Vue.extend({\n  name: 'CoverageGraph',\n  components: {\n    PageHeader,\n    SearchInputVue,\n    RelationGraph\n  },\n  data() {\n    return {\n      rawData: {\n        nodes: [],\n        links: []\n      },\n      renderData: {\n        nodes: [] as any[],\n        links: [] as { from: string; to: string; text?: string }[]\n      },\n      unLoadExpandNodes: [] as string[],\n      height: document.body.clientHeight - 124,\n      graphOptions: {\n        layouts: [\n          {\n            label: '布局',\n            layoutName: 'tree',\n            layoutClassName: 'seeks-layout-center',\n            from: 'left',\n            defaultNodeShape: 2,\n            distance_coefficient: 1,\n            defaultLineShape: 4,\n            defaultNodeBorderWidth: 0,\n            defaultLineColor: '#cccccc',\n            defaultNodeColor: '#43a2f1',\n            min_per_width: '400',\n            min_per_height: '300'\n          }\n        ],\n        defaultExpandHolderPosition: 'right',\n        zoomToFitWhenRefresh: false,\n        moveToCenterWhenRefresh: true\n      },\n      keyword: ''\n    }\n  },\n  computed: {\n    ...mapGetters(['currentModuleInfo', 'currentInstanceInfo'])\n  },\n  mounted() {\n    if (this.$route.query.path) {\n      this.keyword = decodeURIComponent(this.$route.query.path as string)\n    }\n    this.getInitGraphData(0)\n  },\n  methods: {\n    /**\n     * 获得init数据(api)\n     */\n    async getInitGraphData(type: number) {\n      if (type === 1 && !this.keyword.trim()) {\n        this.renderData.nodes = this.rawData.nodes\n        this.renderData.links = this.rawData.links\n        this.renderGraphData()\n        return\n      }\n      const loadingInstance = Loading.service({\n        target: '#relationGraphDiv',\n        text: '数据加载中'\n      })\n      try {\n        const { data } = await API.Instance.getCoverageGraphRootData({\n          instanceId: this.currentInstanceInfo.id,\n          name: this.keyword,\n          id: ''\n        })\n        setTimeout(() => loadingInstance.close(), 500)\n        if (!data.length) {\n          if (type === 0) {\n            this.$message.warning('暂无覆盖率图谱数据')\n          } else {\n            this.$message.warning(`暂无 ${this.keyword} 相关类名`)\n          }\n          "

二、br 换行(可以使用v-html)

demo:

<p v-html="info"></p>
data() {
   return {
     activeName: 'first',
     info: '1、优化批量上传图片<br/>2、优  化时间'
   }
 },

三、把br替换成\n换行

<p style="white-space: pre-wrap;">{{changeLine(info)}}</p>

data(){
	return{
		info: '1、优化批量上传图片<br/>2、优化时间'
	}
},
methods:{
	changeLine(str){
		return str.replace(/<br>/g,'\n')
	}
}

附带:

参考文章:https://blog.csdn.net/qq_41287158/article/details/117588459   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/602082.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

通配符证书价格350元

通配符SSL证书是一种特殊的域名SSL证书&#xff0c;这款SSL证书默认保护主域名以及主域名下的所有子域名&#xff0c;因此&#xff0c;子域名比较多的个人或者企事业单位开发者都倾向于选择通配符SSL证书来简化SSL证书管理过程&#xff0c;节省购买SSL证书的资金&#xff0c;降…

前端如何设置div可滚动,且设置滚动条颜色

在前端中&#xff0c;设置 div 为可滚动并通过 CSS 自定义滚动条的颜色并不是所有浏览器都直接支持的功能&#xff0c;因为滚动条的样式在很大程度上取决于操作系统和浏览器的默认样式。然而&#xff0c;你可以使用某些 CSS 属性来尝试自定义滚动条的外观&#xff0c;这些属性在…

JavaEE概述 + Maven

文章目录 一、JavaEE 概述二、工具 --- Maven2.1 Maven功能 仓库 坐标2.2 Maven之项目构建2.3 Maven之依赖管理 三、插件 --- Maven Helper 一、JavaEE 概述 Java SE、JavaEE&#xff1a; Java SE&#xff1a;指Java标准版&#xff0c;适用于各行各业&#xff0c;主要是Java…

2024 Flutter 一季度热门 issue/roadmap 进展和个人感触闲聊

因为最近的《Flutter&#xff1a;听说你最近到处和人说我解散了&#xff1f;》相关事件之后&#xff0c;不少人对于目前 Flutter 的一些进度情况比较关心&#xff0c;刚好这里做一个简要汇总&#xff0c;报告几个过去一季度相关的热门 issue/roadmap 情况&#xff0c;另外这些天…

邮件群发系统的效率怎么样?如何评估性能?

邮件群发系统的使用方法&#xff1f;邮件群发工具的关键功能&#xff1f; 邮件群发系统已成为企业、组织及个人进行信息沟通的重要工具。然而&#xff0c;当我们谈论邮件群发系统的效率时&#xff0c;我们需要从多个维度来全面分析和评估。AokSend就来介绍一下。 邮件群发系统…

ReactFlow的ReactFlow实例事件传参undefined处理状态切换

1.问题 ReactFlow的ReactFlow实例有些事件我们在不同的状态下并不需要&#xff0c;而且有时候传参会出现其它渲染效果&#xff0c;比如只读状态下我们不想要拖拉拽onEdgesChange连线重连或删除的功能。 2.思路 事件名称类型默认值onEdgesChange(changes: EdgeChange[]) >…

AI大模型探索之路-训练篇17:大语言模型预训练-微调技术之QLoRA

系列篇章&#x1f4a5; AI大模型探索之路-训练篇1&#xff1a;大语言模型微调基础认知 AI大模型探索之路-训练篇2&#xff1a;大语言模型预训练基础认知 AI大模型探索之路-训练篇3&#xff1a;大语言模型全景解读 AI大模型探索之路-训练篇4&#xff1a;大语言模型训练数据集概…

浅谈消息队列和云存储

1970年代末&#xff0c;消息系统用于管理多主机的打印作业&#xff0c;这种削峰解耦的能力逐渐被标准化为“点对点模型”和稍复杂的“发布订阅模型”&#xff0c;实现了数据处理的分布式协同。随着时代的发展&#xff0c;Kafka&#xff0c;Amazon SQS&#xff0c;RocketMQ&…

基于大数据+Hadoop的豆瓣电子图书推荐系统实现

&#x1f339;作者主页&#xff1a;青花锁 &#x1f339;简介&#xff1a;Java领域优质创作者&#x1f3c6;、Java微服务架构公号作者&#x1f604; &#x1f339;简历模板、学习资料、面试题库、技术互助 &#x1f339;文末获取联系方式 &#x1f4dd; 系列文章目录 基于大数…

组合模式(Composite)——结构型模式

组合模式(Composite)——结构型模式 组合模式是一种结构型设计模式&#xff0c; 你可以使用它将对象组合成树状结构&#xff0c; 并且能通过通用接口像独立整体对象一样使用它们。如果应用的核心模型能用树状结构表示&#xff0c; 在应用中使用组合模式才有价值。 例如一个场景…

新能源汽车充电站智慧充电电能服务综合解决方案

安科瑞薛瑶瑶18701709087/17343930412 ★解决方案 ✔目的地充电-EMS微电网平台 基于EMS解决方案从设备运维的角度解决本地充电的能量管理及运维问题&#xff0c;与充电管理平台打通数据&#xff0c;为企业微电网提供源、网、荷、储、充一体化解决方案。 ✔运营场站--电能服务…

​「Python绘图」绘制太极图

python 绘制太极 一、预期结果 二、核心代码 import turtlepen turtle.Turtle()print("开始绘制太极")radius 100 pen.color("black", "black") pen.begin_fill() pen.circle(radius/2, 180) pen.circle(radius, 180) pen.left(180) pen.circ…

英语口语情景对话视频软件分享!

在当今全球化的时代&#xff0c;英语已成为一种通用的国际语言。为了提高英语口语能力&#xff0c;越来越多的人选择使用英语口语情景对话视频软件。本文将为您推荐几款备受欢迎的英语口语情景对话视频软件&#xff0c;帮助您轻松提高英语口语水平。 AI外语陪练 AI外语陪练软件…

营养补充品软胶囊:弹性测试与市场表现的深度解析

营养补充品软胶囊&#xff1a;弹性测试与市场表现的深度解析 在追求健康生活的时代&#xff0c;营养补充品市场蓬勃发展&#xff0c;其中软胶囊作为一种方便、易吸收的剂型&#xff0c;受到了消费者的广泛欢迎。然而&#xff0c;在这个竞争激烈的市场中&#xff0c;如何确保产…

推荐5个AI工具平替GPT

随着AI技术的快速发展&#xff0c;AI写作正成为创作的新风口。但是面对GPT-4这样的国际巨头&#xff0c;国内很多小伙伴往往望而却步&#xff0c;究其原因&#xff0c;就是它的使用门槛高&#xff0c;还有成本的考量。 不过&#xff0c;随着GPT技术的火热&#xff0c;国内也涌…

window11事件查看器中“在事件中只要触发此事件,就会执行相关非XX.xml脚本”

在事件中只要触发此事件&#xff0c;就会执行相关非XX.xml脚本 一、操作过程 1、在时间查看器中&#xff0c;将任务附加到此事件上 2、按照提示逐步下一步添加完成 3、只要触发1中的事件&#xff0c;那么就会执行对应的关联脚本xx.xml。 二、解决办法 1、通过开始菜单搜索打…

riscv交叉编译ports软件@FreeBSD15

当前FreeBSD的riscv版本下&#xff0c;软件包还很贫乏&#xff0c;再加上RISCV的板子有很多种&#xff0c;大部分时候都需要自己动手编译。但是在RISCV环境下编译太慢了&#xff0c;所以我们要使用交叉编译&#xff0c;在很快的AMD64服务器上交叉编译RISCV的软件包。 这里使用…

Promise魔鬼面试题

文章目录 题目解析难点分析分析输出step1step2step3step4step5step6 参考/致谢&#xff1a;渡一袁老师 题目 Promise.resolve().then(() > {console.log(0);return Promise.resolve(4);}).then((res) > {console.log(res);});Promise.resolve().then(() > {console.l…

基于FPGA的数字信号处理(10)--定点数的舍入模式(1)四舍五入round

1、前言 将浮点数定量化为定点数时&#xff0c;有一个避不开的问题&#xff1a;某些小数是无法用有限个数的2进制数来表示的。比如&#xff1a; 0.5(D) 0.1(B) 0.1(D) 0.0001100110011001~~~~(B) 可以看到0.5是可以精准表示的&#xff0c;但是0.1却不行。原因是整数是离散的…

AngusTester安装请求代理

一、介绍 请求代理程序(AngusProxy)提供两个方面作用&#xff1a; 代理Http和WebSocket协议接口调试请求&#xff0c;解决浏览器跨域限制问题。对代理请求客户化处理支持&#xff0c;允许用户对代理请求进行二次处理&#xff0c;如&#xff1a;请求参数签名。 二、类型 为了…