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

news2024/11/17 5:32:27

一、背景: 后端接口返回数据以\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   

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

企业内部文化社区究竟有哪些好处?

首先&#xff0c;我们来了解下&#xff0c;企业内耗是什么? 在企业文化管理中&#xff0c;内耗是一个常见的问题&#xff0c;它会影响企业的团队协作、执行效率和绩效表现。在2023《哈佛商业评论》中国年会上&#xff0c;北大汇丰商学院管理实践教授陈玮分享了他对组织管理的…

vue下载文件,获取header头文件名乱码,下载文件名有下划线的解决

后台以数据流将文件返回&#xff0c;将文件名放在header头里&#xff0c;是中文名&#xff0c;有乱码&#xff0c;如图 访问网络使用的是axios&#xff0c;在 // 响应拦截器 service.interceptors.response.use((res) > {........ if (res.config.responseType blob) {//文…

第十六篇:数据库性能优化:从基础到高级的全面指南

数据库性能优化&#xff1a;从基础到高级的全面指南 1. 引言 在数字化的浪潮中&#xff0c;数据库作为信息系统的核心组件&#xff0c;其性能的优劣直接关系到企业的运营效率和市场竞争力。数据库性能优化不仅是一项技术挑战&#xff0c;更是一项战略任务。它要求我们深入理解…

数据结构(栈):中缀表达式转后缀表达式题型的快速图解法(求栈中操作符等)

2024/5/14&#xff1a; 学编译原理的时候接触到了递归树的画法&#xff0c;中缀转后缀的解题过程和编译原理中的递归树有异曲同工之妙。今日解题的时候想了一下图解法&#xff0c;遂记录&#xff0c;本质上是对递归树的改进。 图解原理概述 以表达式 ab*(c-d)e 为例&#xff0c…

Redis一主二从三哨兵配置

一.安装Redis&#xff08;三台主机&#xff09; 1.下载redis安装程序 访问https://redis.io/download/ 进行对应系统和版本的下载&#xff0c;以下以redis的7.0.5为例安装 2.安装redis mkdir -p /data/soft #创建软件安装程序的存放目录 cd /data/soft #进入目录&#xff0…

【35分钟掌握金融风控策略27】贷中风控策略与客户运营体系

目录 贷中风控策略与客户运营体系 贷中风控日标 贷中风控数据源 贷中风控策略与客户运营体系 贷中是风控的第二道防线&#xff0c;贷中阶段风控的重点工作就是存量客户风控及运营。在当下&#xff0c;新客市场趋于饱和且获客成本越来越高&#xff0c;所以&#xff0c;在做好…

webpack5基础和配置

初步体验webpack打包 webpack是一个静态资源打包工具。 它会以一个或多个文件作为打包的入口&#xff0c;将我们整个项目所有文件编译组合成一个或多个文件输出出去。 输出的文件就是编译好的文件&#xff0c;就可以在浏览器段运行了。 1.初始化最简单的一个目录文件&#xff…

SSM整合-前后端分离-实现增删改查 (下)

主流框架SSM 实现功能03-添加家居信息需求分析/图解思路分析代码实现注意事项和细节 实现功能04-显示家居信息需求分析/图解思路分析代码实现 实现功能05-修改家居信息需求分析/图解思路分析代码实现注意事项和细节 实现功能06-删除家居信息需求分析/图解思路分析代码实现课后作…

智慧安防监控EasyCVR视频汇聚管理平台视频播放花屏的原因分析及处理

智慧安防监控EasyCVR视频管理平台能在复杂的网络环境中&#xff0c;将前端设备统一集中接入与汇聚管理。国标GB28181协议视频监控/视频汇聚EasyCVR平台可以提供实时远程视频监控、视频录像、录像回放与存储、告警、语音对讲、云台控制、平台级联、磁盘阵列存储、视频集中存储、…

解决ubuntu 暂时不能解析域名“cn.archive.ubuntu.com”问题

问题描述 E: 无法下载 http://security.ubuntu.com/ubuntu/pool/main/c/curl/curl_7.68.0-1ubuntu2.22_amd64.deb 暂时不能解析域名“cn.archive.ubuntu.com” 解决方法 sudo service network-manager stopsudo rm /var/lib/NetworkManager/NetworkManager.statesudo servi…

探讨 cs2019 c++ 的STL 库中的模板 conjunction 与 disjunction

&#xff08;1&#xff09;在 STL 库源码中这俩模板经常出现&#xff0c;用来给源码编译中的条件选择&#xff0c;模板的版本选择等提供依据。先给出其定义&#xff1a; 以及&#xff1a; 可以得出结论&#xff1a; conj 是为了查找逻辑布尔型模板参数中的第一个 false &#x…

2024CKE中国婴童展

举办地点&#xff1a;上海新国际博览中心 举办时间&#xff1a;2024年10月16-18日 同期展会&#xff1a;CTE中国玩具展、CPE中国幼教展、CLE中国授权展 展会规模&#xff1a;230,000平米 展商数量&#xff1a;2,500 参展品牌&#xff1a;5,212 …

hadoop大数据的一些知识点--Map reduce编程

实验4 MapReduce编程(2) 本实验的知识地图如图4-1所示&#xff08; 表示重点 表示难点&#xff09;。 图4-1 实验4MapReduce编程(2)知识地图 一、实验目的 1. 理解YARN体系架构。 2. 熟练掌握YARN Web UI界面的使用。 3. 掌握YARN Shell常用命令的使用。 4. 了解YARN编程之…

最新版Ceph( Reef版本) nfs导出

1 创建一个nfs集群 ceph nfs cluster create <cluster_id> [<placement>]# ceph nfs cluster create mycluster ceph-nfs-server 2. 在ceph-164,ceph-165 host建立一个高可用的nfs # ceph nfs cluster create mycluster --placementceph-164,ceph-1653. 导出nfs集群…

API低代码平台介绍3-异构数据源的数据查询功能

异构数据源的数据查询功能 在上一篇文章中我们通过API平台定义了一个最基本的数据查询接口&#xff0c;本篇文章我们将上升难度&#xff0c;在原有接口的基础上&#xff0c;实现在MySQL数据库和Oracle数据库同时进行数据查询。   什么场景会需要同时对异构数据源进行查询&…

Java——封装

要想搞明白封装&#xff0c;首先要清楚什么是 包 包的概念&#xff1a; 在面向对象的体系中&#xff0c;提出了一个软件包的概念&#xff0c;即&#xff1a;为了更好的管理类&#xff0c;把多个类收集在一起称为一组&#xff0c;称为软件包。 包的作用&#xff1a; 1、一个…

“打工搬砖记”中吃什么的轮盘功能实现(二)

文章目录 打工搬砖记转盘主要的逻辑实现转盘的素材小结 打工搬砖记 先来一个吃什么轮盘的预览图&#xff0c;这轮盘文案加字呈圆形铺出来&#xff0c;开始后旋转到指定的选项处停下来。 已上线小程序“打工人搬砖记”&#xff0c;可以扫码进行预览观看。 转盘主要的逻辑实现…

springMVC基础使用(示例)

maven依赖&#xff08;javax.servlet-api版本与spring-webmvc班恩要匹配不然会报java.lang.NoSuchMethodError: javax.servlet.http.HttpServletRespons&#xff09;&#xff1a; <dependencies><dependency><groupId>javax.servlet</groupId><arti…

Java面试题:ConcurrentHashMap

ConcurrentHashMap 一种线程安全的高效Map集合 jdk1.7之前 底层采用分段的数组链表实现 一个不可扩容的数组:segment[] 数组中的每个元素都对应一个HashEntry数组用以存放数据 当放入数据时,根据key的哈希值找到对应的segment数组下标 找到下标后就会添加一个reentrantlo…

Open AI再次定义AI PC?

从传统的文字交互&#xff0c;到语音和图像交互——Open AI再次提升了人们对AI PC的想象空间。 这种更贴近人类间交互的模式&#xff0c;会多大程度改变目前PC的生态&#xff1f; 随着苹果M4芯片、高通骁龙X的发布&#xff0c;AI PC也逐渐成为了市场热议的产品。 从各家PC厂…