在前端日常的开发当中,我们其实还是比较容易与树形结构打交道的。常见的比如,我们需要根据后端返回的菜单列表生成页面中树形菜单。也有可能是将列表数据转换成树形选择器的选项数据等。也有可能是从树形的数据当中找到某个数据等。
那么下面我将我在项目当中使用的处理方法分享出来。
1. 将列表转换成树形结构
1.1 我的思路
这种思路的前提条件是所有的父节点都在在子节点的前面出现。首先循环遍历列表,将每一项都放入一个map中,同时判断每一项的父节点是否在map对象中,如果存在就将这一项放入到这个父节点的children属性下面。这样循环结束就可以生成树形的数据了。
1.2 代码实现
const createTree = function (list=[]) {
let tree = [];
let map = {};
list.forEach(item => {
const newItem = {
id: item.id,
pid: item.pid,
name: item.name,
code: item.code,
children: [],
};
map[item.id] = newItem;
// 判断是否是根节点
if (item.pid === -1) {
tree.push(newItem);
} else {
map[newItem.pid].children.push(newItem);
}
});
return tree;
};
const list = [
{
id: 1,
pid: -1,
name: '张三1',
code: '1'
},
{
id: 11,
pid: 1,
name: '张三11',
code: '11'
},
{
id: 12,
pid: 1,
name: '张三12',
code: '12'
},
{
id: 13,
pid: 1,
name: '张三13',
code: '13'
},
{
id: 2,
pid: -1,
name: '张三2',
code: '2'
},
{
id: 21,
pid: 2,
name: '张三2',
code: '21'
},
{
id: 211,
pid: 21,
name: '张三211',
code: '211'
},
]
console.log(createTree(list));
1.3 升级改造
我们上面的方法是有个前提条件的那就是父节点必须在子节点之前出现,否则就会出现问题。那么如何处理父节点在子节点之后出现呢。
我们可以再加个map,用于存放那些父节点还没出现的子节点,然后循环遍历的时候判断这个暂存区是否有自己的子节点,如果有就将他们放入到自己的children属性里面。
代码如下
const createTree = function (list=[]) {
const tree = [];
const map = {};
const waitPushObj = {};
list.forEach(item => {
const newItem = {
id: item.id,
pid: item.pid,
name: item.name,
code: item.code,
children: [],
};
map[item.id] = newItem;
// 判断是否是根节点
if (item.pid === -1) {
tree.push(newItem);
} else if (map[item.pid]) {
map[item.pid].children.push(newItem);
} else {
if (!waitPushObj[item.pid]) {
waitPushObj[item.pid] = [];
}
waitPushObj[item.pid].push(newItem);
}
// 判断暂存区是否有自己的子节点
if (waitPushObj[item.id]) {
newItem.children = waitPushObj[item.id];
delete waitPushObj[item.id];
}
// 可以不加这个判断
if (!map[item.id]) {
map[item.id] = newItem;
}
});
return tree;
};
const list = [
{
id: 11,
pid: 1,
name: '张三11',
code: '11'
},
{
id: 12,
pid: 1,
name: '张三12',
code: '12'
},
{
id: 13,
pid: 1,
name: '张三13',
code: '13'
},
{
id: 21,
pid: 2,
name: '张三2',
code: '21'
},
{
id: 1,
pid: -1,
name: '张三1',
code: '1'
},
{
id: 211,
pid: 21,
name: '张三211',
code: '211'
},
{
id: 2,
pid: -1,
name: '张三2',
code: '2'
},
]
console.log(createTree(list));
2. 查找某个元素
2.1 利用迭代的方式查找
const tree = [
{
"id": 1,
"pid": -1,
"name": "张三1",
"code": "1",
"children": [
{
"id": 11,
"pid": 1,
"name": "张三11",
"code": "11",
"children": []
},
{
"id": 12,
"pid": 1,
"name": "张三12",
"code": "12",
"children": []
},
{
"id": 13,
"pid": 1,
"name": "张三13",
"code": "13",
"children": []
}
]
},
{
"id": 2,
"pid": -1,
"name": "张三2",
"code": "2",
"children": [
{
"id": 21,
"pid": 2,
"name": "张三2",
"code": "21",
"children": [
{
"id": 211,
"pid": 21,
"name": "张三211",
"code": "211",
"children": []
}
]
}
]
}
]
const findNode = function (tree, id) {
const list = [...tree];
let p = list.shift();
while (p) {
if (p.id === id) return p;
if (p.children) {
list.push(...p.children)
}
p = list.shift();
}
return null;
}
console.log(findNode(tree, 211))