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