应用场景
项目中有很多场景会遇到需要将数据转换成树形结构来展示内容的时候,比如:进入页面的菜单展示、树形列表的展示或者是父子联动的勾选框展示等等
原数据
假如你拿到的数据是一个集合,如下格式:
分析原数据关系
比如这个nodeId是0.1.4的节点,他的parentId是0.1,那就说明nodeId是0.1的节点就是他的父节点,nodeId是0.1的节点的parentId是0,就说明nodeId是0的节点是他的父节点
直观理解如下:
let adreeJson = [
{nodeId: 1, name: '安徽省', parentId: 0},
{nodeId: 2, name: '辽宁市', parentId: 0},
{nodeId: 3, name: '广东省', parentId: 0},
{nodeId: 4, name: '西安市', parentId: 1},
{nodeId: 5, name: '山西', parentId: 1},
{nodeId: 6, name: '莲湖区', parentId: 4},
{nodeId: 7, name: '雁塔区', parentId: 4},
{nodeId: 8, name: '深圳市', parentId: 3},
{nodeId: 9, name: '上海', parentId: 8},
]
需要解析成
let adressTree = [
{
nodeId: 1, name: '安徽省', parentId: 0,
child: [
{
nodeId: 4, name: '西安市', parentId: 1,
child: [
{nodeId: 6, name: '莲湖区', parentId: 4},
{nodeId: 7, name: '雁塔区', parentId: 4},
]
},
{
nodeId: 5, name: '宝鸡市', parentId: 1
},
]
},
{
nodeId: 2, name: '辽宁市', parentId: 0,
child: []
},
{
nodeId: 3, name: '广东省', parentId: 0,
child: [
{
nodeId: 8, name: '深圳市', parentId: 3,
child: [
{nodeId: 9, name: '上海', parentId: 8}
]
}
]
},
]
解决
方法
我在项目中是定义了两个全局方法,然后在需要使用的vue页面使用即可,代码如下:
//全局的方法,别忘了在main.js里面注册
//传入数组,区分出第一层数组节点
export function getTop(array) {
return arry.filter(item => item.nodeId == item.parentId || item.parentId == null)
}
//pArry:是getTop返回的一级节点数据
//array: 拿到的原始数组
// 如果nodeId和parentId相同,放数据放在children里,就是第二层节点,依次递归
export function getChild(pArry, array) {
pArry.forEach(idt => {
idt.children = arry.filter(item => idt.nodeId == item.parentId)
if ((idt.children).length > 0) {
getChild(idt.children, arry)
}
})
return pArry
}
//要使用的vue文件里面
stackV2(data).then(res=>{
if(res.data.length>0){
let topTree = this.getTop(res.data)
this.tableData = this.getChild(topTree, res.data)
}
})
另一种递归方法
原理和上面差不多,先是获取父节点,再判断是不是父节点,不是父节点就放在当前节点的子节点内
function toTree(arrays) {
let result = []
//判断拿到的数据是否是数组,如果值是Array,则为true; 否则为false。
if (!Array.isArray(arrays)) {
return result
}
//深拷贝,否则会影响原数组
let node = JSON.parse(JSON.stringify(arrays))
//根据父节点进行拼接子节点,先判断里面是否有子节点,如果已经有的话,先删了
node.forEach(item => delete item.child)
let map = {}
let newNode = []
//把每一项的引用放入map对象里
node.forEach(item => map[item.id] = item)
node.forEach(dt => {
let parents = map[dt.pid]
if (parents) {
//如果 map[dt.pid] 有值 则 parents 为 dt 的父级
//判断 parents 里有无child 如果没有则创建 如果有则直接把 dt push到child里
((parents.child) || (parents.child = [])).push(dt)
//等同于:
// if (!parents.child) {
// parents.child = []
// }
// (parents.child).push(dt)
} else {
newNode.push(dt)
}
})
return newNode
}
console.log(toTree(array))