跳到主要内容

日常开发中树形结构数据的几种处理方式

· 阅读需 5 分钟
编程范儿

写业务代码写多了发现大部分时间都在处理各种格式的数据,而尤以数组和对象类型的数据为主。数据主要来源又分为:从云端接口获取的数据、本地表单提交的数据 或直接使用 Sql 语句从数据库中读取的数据,甚至还有从静态文件中通过 fetch 请求到的文本转化为特定格式的数据。

不管数据的来源如何,我们的工作重心永远都是在把源数据处理成最终符合我们需求的数据。

下面展示的是一个嵌套的对象数组结构的数据,通常在渲染菜单或创建多层分类的时候用到。

树形结构增加属性

如果我们要给菜单的每一项增加一个层级的属性,则需要通过递归的方式,实现下面这样一个构造的方法:

const arrayTreeAddLevel = (array, levelName = 'level', childrenName = 'children') => {
if (!Array.isArray(array)) return [];
const recursive = (array, level = 0) => {
level++;
return array.map(v => {
v[levelName] = level;
const child = v[childrenName];
if (child && child.length) recursive(child, level);
return v;
})
}
return recursive(array)
}

然后,我们将树形结构的数据通过参数传入调用后:

arrayTreeAddLevel(treeData);

数据经过处理后,输出如下:

树形结构拍平

如果是将树形结构的数据拍平,返回一个一维数组呢?

export function flatTree(data, children?) {
const arrList = [];
const config = {
childrenList: children || "children"
};

for (const d of data) {
adaptToChildrenList(d);
}

function adaptToChildrenList(o) {
const obj = Object.entries(o).reduce(
(a, [k, v]) => (k === config.childrenList ? a : ((a[k] = v), a)),
{}
);
arrList.push(obj);
if (o[config.childrenList] && o[config.childrenList].length > 0) {
for (const l of o[config.childrenList]) {
adaptToChildrenList(l);
}
}
}
return arrList;
}

通过以上的函数,成功返回了我们想要的数据:

按照某个字段排序

在菜单的使用场景中,我们需要对同级的数组按照某个字段进行排序:

function sortTree(data, attr = 'rank') {
const menus = data.sort(
(a, b) => {
return a[attr] - b[attr];
}
);
menus.forEach(
v => v.children && (v.children = sortTree(v.children))
);
return menus;
}

通过切换按钮,可直观观察排序前后的数据变化。

太空编程
分享硬核的前端编程知识。
想及时了解前端相关资讯,请关注作者公众号“太空编程”,回复关键字,获取丰富的学习资料。