使用场景
如渲染项目的目录结构
最终效果
实现原理
- 将树型数据转换为一维数组后用 v-for 渲染
- 连接线通过合适大小的div 边框绘制
- 缩进通过添加和深度匹配的合适大小的空白 div 实现
范例代码
<template> <view class="container"> <div v-for="(item,index) in oneArrTree" :key="index" class='itemBox'> <div v-for="(blankItem,blankIndex) in (item.deep-1)" :key="blankIndex" class='blankBox'> <div class='linkBox' v-if='item.deeplist&&item.deeplist.includes(blankItem)'> </div> </div> <div class='nodeBox' v-if="index !==0"></div> <div class='firBox' v-else></div> <div>{{item.label}}</div> </div> </view> </template> <script> // 树型数据转化为一维数组(含每个节点的深度和深度列表) function getOneArr(data) { let tree if (Object.prototype.toString.call(data) === '[object Object]') { // 传入的数据为对象时,深拷贝为数组 tree = JSON.parse(JSON.stringify([data])) } let newData = [] let deep = 0 const expanded = datas => { deep++ if (datas && datas.length > 0) { let initDeep = deep datas.forEach(item => { let newItem = JSON.parse(JSON.stringify(item)) delete newItem.children newItem.deep = initDeep newData.push(newItem); newData.forEach(oldItem => { if (!oldItem.deeplist) { oldItem.deeplist = [] } if (oldItem.deep > newItem.deep) { if (!oldItem.deeplist.includes(newItem.deep)) { oldItem.deeplist.push(newItem.deep) } } }) if (item.children) { expanded(item.children); } deep = initDeep }) } }; expanded(tree); return newData; } export default { mounted() { this.oneArrTree = getOneArr(this.treeData) }, data() { return { oneArrTree: [], treeData: { "label": "doshome", "children": [{ "label": ".hbuilderx", "children": [{ "label": "launch.json" }, ] }, { "label": ".vite", }, { "label": "pages", "children": [{ "label": "index", "children": [{ "label": "inde.vue" }, ] }, { "label": "login" }, ] }, { "label": "static", }, ] } } }, } </script> <style> .container { padding: 30px; } .itemBox { display: flex; } .firBox { height: 12px; width: 20px; } .blankBox { height: 12px; width: 40px; } .linkBox { height: 12px; width: 0px; border-left: 1px solid black; } .nodeBox { border-left: 1px solid black; border-bottom: 1px solid black; height: 12px; width: 20px; } </style>