后端返回如下数据,需根据parentId组装成Tree数据的格式,即所有的子节点都在父节点的children之下
[
{
"id": 1,
"name": "bug菜单",
"parentId": null,
"type": 1
},
{
"id": 2,
"name": "404",
"parentId": null,
"type": 1
},
{
"id": 3,
"name": "123",
"parentId": 1,
"type": 1
},
{
"id": 4,
"name": "222",
"parentId": 1,
"type": 1
},
{
"id": 7,
"name": "333",
"parentId": 3,
"type": 1
},
{
"id": 8,
"name": "777",
"parentId": 7,
"type": 1
},
{
"id": 10,
"name": "888",
"parentId": 8,
"type": 1
},
{
"id": 11,
"name": "999",
"parentId": null,
"type": 1
},
{
"id": 12,
"name": "10",
"parentId": 10,
"type": 1
}
]
先定义一个声明接口:
interface treeInter {
id: number;
parentId: number;
type: number;
children: treeInter[]
}
// 后端数据
let menuData = reactive({
list: [] as treeInter[]
})
// 递归
const filterTree = (arr: treeInter[], id: null | number = null): treeInter[] => {
// 第一次id未赋值,返回根节点
// 查找parentId为此id的项,并进行递归调用
return arr.filter(e => e.parentId === id)
.map(e => {
e.children = filterTree(arr, e.id)
return e
})
}
// 使用
filterTree(menuData.list)
const mapTree = (data: treeInter[]) => {
// 父id映射表
// reduce的第二个参数为初始默认值
const idMapping = data.reduce((acc: { [key: string]: number }, el: treeInter, i: number) => {
acc[el.id] = i;
return acc;
}, {});
let tempList: treeInter[] = []
// data 数组里的每个元素都是内存里的一个对象引用,
// forEach循环里的el变量其实是指向内存里的一个对象,parentEl也引用了一个对象。
data.forEach((el: treeInter) => {
// 用映射表找到父元素
let parentEl = data[idMapping[el.parentId]];
// 判断根节点或没找到父元素时
if (el.parentId === null||!parentEl) {
tempList.push(el)
return;
}
// 把当前元素添加到父元素的`children`数组中
parentEl.children = [...(parentEl.children ?? []), el]
});
return tempList
}
const setTree = (data: treeInter[]) => {
// 根节点数据
let treeList: treeInter[] = []
// 子节点数据
let childList: treeInter[] = []
// 若没有在数据中找到与parentId相匹配的id
// 则默认展示(搜索时有用到)
let parentSet = new Set()
// 区分根节点和子节点,并为children赋初值
for (let i of data) {
i.children = []
parentSet.add(i.id)
if (parentSet.has(i.parentId) ) {
childList.push(i)
} else {
treeList.push(i)
}
}
// 根节点和子节点比较
treeList.forEach(e => {
childList.forEach(c => {
// 若第一层数据中有对应的parentId
if (e.id == c.parentId) {
e.children.push(c)
} else {
// 查看子节点中,是否有对应的父节点
deepFindChild(e.children, c)
}
})
})
// 递归函数
function deepFindChild(list: treeInter[], c: treeInter) {
list.forEach((e: treeInter) => {
if (e.id == c.parentId) {
e.children.push(c)
} else {
deepFindChild(e.children, c)
}
})
}
return treeList
}
const setTree = (data: treeInter[]) => {
// 顶层数据
let treeList: treeInter[] = []
// 子数据
let childList: treeInter[] = []
// 若没有在数据中找到与parentId相匹配的id
// 则默认展示(搜索时有用到)
let parentSet = new Set()
// 区分顶层数据节点和子节点
for (let i of data) {
i.children = []
parentSet.add(i.id)
if (parentSet.has(i.parentId) ) {
childList.push(i)
} else {
treeList.push(i)
}
}
// 将子节点数据中,有对应的父子两两组合
for (let i = 0; i < childList.length; i++) {
for (let j = childList.length - 1; j >= 0; j--) {
if (childList[i].id === childList[j].parentId) {
childList[i].children.push(childList[j])
}
}
}
// 组合完后,于根节点再进行组装
treeList.forEach(e => {
childList.forEach(c => {
if (c.parentId === e.id) {
e.children.push(c)
}
})
})
return treeList
}