需求
最近遇到一个需求,平时被后台惯着直接返回了树形结构给到前端,前端对这种嵌套类型的数据(如地区的级联或菜单的树形结构)省掉了一层处理。换了个后台开发返回了扁平化的数组数据给到前端自己去处理如下 data。突然有点慌 ……
const data = [
{
“area_id”: 5,
“name”: “ 广东省 ”,
“parent_id”: 0,
},
{
“area_id”: 6,
“name”: “ 广州市 ”,
“parent_id”: 5,
},
{
“area_id”: 7,
“name”: “ 深圳市 ”,
“parent_id”: 5,
},
{
“area_id”: 4,
“name”: “ 北京市 ”,
“parent_id”: 3,
},
{
“area_id”: 3,
“name”: “ 北京 ”,
“parent_id”: 0,
},
{
“area_id”: 2,
“name”: “ 测试子地区 ”,
“parent_id”: 1,
},
{
“area_id”: 1,
“name”: “ 测试地区 ”,
“parent_id”: 0,
}
]
emmm,换个念头想想也刚好锻炼锻炼,撸起袖子干吧,然后就总结了以下两种整理方法~
方法一——递归
在这种那么适合递归的场景,怎么能少了递归这个角色呢?第一种方法,递归出场!献上递归宝器~
function toTreeData(data,pid){
function tree(id) {
let arr = []
data.filter(item => {
return item.parent_id === id;
}).forEach(item => {
arr.push({
area_id: item.area_id,
label: item.name,
children: tree(item.area_id)
})
})
return arr
}
return tree(pid) // 第一级节点的父 id,是 null 或者 0,视情况传入
}
恩,姿势摆好,在控制台里执行一下
哎哟,不错哦~ 后台小哥哥再也不担心需要返回什么数据给我了。不过,该方法有个缺点,在我使用组件的时候需要的数据结构中,如果子级没有数据 children 返回[]。恩,有点问题,但是还是可以优化的,优化的代码我会那么容易给出来吗?你已经是个成熟的程序猿了,需要学会自己优化代码了!!!
方法二——对象
对象在我眼里一直是倚天屠龙宝刀的存在,了解到其中的奥妙便形同有一武林秘籍傍身。当然,没用好就相当于一堆废铁,甚至将导致一些不可预料的结果。
function setTreeData(arr) {
// 删除所有 children, 以防止多次调用
arr.forEach(function (item) {
delete item.children;
});
let map = {}; // 构建 map
arr.forEach(i => {
map[i.area_id] = i; // 构建以 area_id 为键 当前数据为值
});
let treeData = [];
arr.forEach(child => {
const mapItem = map[child.parent_id]; // 判断当前数据的 parent_id 是否存在 map 中
if (mapItem) {// 存在则表示当前数据不是最顶层数据
// 注意: 这里的 map 中的数据是引用了 arr 的它的指向还是 arr,当 mapItem 改变时 arr 也会改变, 踩坑点
(mapItem.children || ( mapItem.children = [] )).push(child); // 这里判断 mapItem 中是否存在 children, 存在则插入当前数据, 不存在则赋值 children 为 [] 然后再插入当前数据
} else {// 不存在则是组顶层数据
treeData.push(child);
}
});
return treeData;
};
console.log(setTreeData(data)); // 输出整理后的数据
结果我就不执行了,跟递归的结果相似。相比起递归,我更喜欢这种方法。不过这种方法有一种容易犯错的地方,就是它会改变原数据,我就在这里踩了好久的坑,所以一开始采用了删除 children 的初始化了一遍。记住了吗,没记住自行重复说三遍!!!
总结
以上简单介绍了两种将扁平化数据转化为递归树的方法,学会了吗,没学会再回去好好撸撸码!!目前我遇到需要将数据整理树形结构的主要在菜单栏或分类的树形结构上,当然还有像省市这种有从属关系的结构。不过就算以后遇到了都唔驶惊啦~ 恩,继续更新总结中 ….