在我们日常开发中,我们经常会遇到树形结构的数据,我们业务中有一些自定义的需求的时候,我们就会去处理他们,本文就列举几种我们常见的情况. 先定义一个树形数据,下文都是这个来测试
// 用于测试的树形数据
const treeData = [ { id: '1', name: '测试1', pId: '0', children: [ { id: '11', name: '测试11', pId: '1', children: [ { id: '111', name: '测试111', pId: '11', children: [ { id: '1111', name: '测试1111', pId: '111' }, { id: '1112', name: '测试1112', pId: '111' } ]
},
{
id: '112',
name: '测试112',
pId: '11',
children: [
{
id: '1121',
name: '测试1121',
pId: '112'
}
]
},
{
id: '113',
name: '测试113',
pId: '11'
}
]
},
{
id: '12',
name: '测试12',
pId: '1',
children: [
{
id: '121',
name: '测试121',
pId: '12'
}
]
},
{
id: '13',
name: '测试13',
pId: '1'
},
{
id: '14',
name: '测试14',
pId: '1'
}
]
},
{
id: '2',
name: '测试2',
pId: '0',
children: [
{
id: '21',
name: '测试21',
pId: '2',
children: [
{
id: '211',
name: '测试211',
pId: '21'
},
{
id: '212',
name: '测试212',
pId: '21'
}
]
},
{
id: '22',
name: '测试22',
pId: '2'
}
]
}
];
扁平化与树形转换
树->扁平
业务中可能需要我们将树形数据转成扁平的发给后端
function treeToFlat(data) {
const result = [];
data.forEach((item) => {
const obj = {
name: item.name,
id: item.id,
pId: item.pId
};
result.push(obj);
if (item.children?.length) {
result.push(...treeToFlat(item.children, item.id));
}
});
return result;
}
console.log(treeToFlat(treeData));//[
{ name: '测试1', id: '1', pId: '0' },
{ name: '测试11', id: '11', pId: '1' },
{ name: '测试111', id: '111', pId: '11' },
{ name: '测试1111', id: '1111', pId: '111' },
{ name: '测试1112', id: '1112', pId: '111' },
{ name: '测试112', id: '112', pId: '11' },
{ name: '测试1121', id: '1121', pId: '112' },
{ name: '测试113', id: '113', pId: '11' },
{ name: '测试12', id: '12', pId: '1' },
{ name: '测试121', id: '121', pId: '12' },
{ name: '测试13', id: '13', pId: '1' },
{ name: '测试14', id: '14', pId: '1' },
{ name: '测试2', id: '2', pId: '0' },
{ name: '测试21', id: '21', pId: '2' },
{ name: '测试211', id: '211', pId: '21' },
{ name: '测试212', id: '212', pId: '21' },
{ name: '测试22', id: '22', pId: '2' }
]
扁平->树
当后端返回给我们的数据,后端没做处理的时候,可能就是扁平化的数据,通过一个标识符表示关系(比如pid),我们就需要转成树壮数据来展示
function tranListToTreeData (list, rootValue) {
var arr = [];
list.forEach((item) => {
if (item.pid === rootValue) {
const children = tranListToTreeData(list, item.id);
if (children?.length) item.children = children;
arr.push(item);
}
});
return arr;
}
console.log(tranListToTreeData(res1, '0'));
数组元素的处理
查找数组元素
let result = {};
function findRecursion(data, key) {
data.forEach((item) => {
if (item.id === key) {
result = item;
}
if (item.children) {
result = findRecursion(item.children, key);
}
});
return result;
}
// 查找 测试1112(1112)
console.log(findRecursion(treeData, '1112'));//{ id: '1112', name: '测试1112', pid: '111' }
替换对象键名
function findRecursion(data, oldName, newName) {
data.forEach((item) => {
item[newName] = item[oldName];
delete item[oldName];
if (item.children) findRecursion(item.children, oldName, newName);
});
}
// name替换为age
findRecursion(treeData, 'name', 'age');
console.log(treeData);
计算节点数量
可以直接使用刚刚转数组那个函数
console.log(treeToFlat(treeData).length); //17
判断节点下有无某个节点
function judgeChildrenHad(data, keys) {
let mark = false;
for (let i = 0; i < data.length; i++) {
if (keys.includes(data[i].id)) {
mark = true;
} else if (data[i].children?.length) {
return judgeChildrenHad(data[i].children, keys);
}
}
return mark;
}
// 判断 测试111(111)后代节点中有无 测试1112(1112)节点
const mark1 = judgeChildrenHad(treeData, ['1112']);
console.log('3. mark1', mark1);// 3. mark1 true
// 判断 测试111(111)后代节点中有无 测试1121(1121)节点
const mark2 = judgeChildrenHad(treeData, ['1121']);
console.log('3. mark2', mark2); // // 3. mark2 false