树结构扁平化方法
功能概述
通过递归遍历树状结构数据,将其转换为扁平化的数组,同时支持提取指定的公共属性。
常用于将多层级的树形数据结构变为单层数组,便于后续操作(如列表渲染、查找等)。
核心代码
函数实现
/**
* @description 树结构扁平化,将树形数据转为平铺数组
* @param {Array} arrs - 树形数据数组
* @param {string} childs - 子节点属性名(如 'children')
* @param {Array} attrArr - 需要提取的公共属性数组,默认为除了子节点字段外的所有属性
* @returns {Array} 返回扁平化的数组
*/
function extractTree(arrs, childs, attrArr) {
let attrList = [];
// 数据校验
if (!Array.isArray(arrs) || !arrs.length) return []; // 非数组或空数组返回空
if (typeof childs !== 'string') return []; // 子节点字段必须为字符串
// 提取属性列表
if (!Array.isArray(attrArr) || (Array.isArray(attrArr) && !attrArr.length)) {
attrList = Object.keys(arrs[0]); // 获取对象的所有属性
attrList.splice(attrList.indexOf(childs), 1); // 移除子节点字段
} else {
attrList = attrArr; // 使用用户自定义的属性数组
}
const list = [];
/**
* @description 递归处理每个节点
* @param {Array} arr - 当前层级数据
*/
const flatten = (arr) => {
arr.forEach((node) => {
const obj = {};
attrList.forEach((key) => {
obj[key] = node[key]; // 提取指定属性
});
list.push(obj); // 添加到结果数组
if (node[childs]) {
flatten(node[childs]); // 递归处理子节点
}
});
return list;
};
return flatten(arrs);
}
用法示例
测试数据
const treeData = [
{
id: 1,
name: '节点1',
children: [
{
id: 2,
name: '节点1-1',
children: [
{ id: 4, name: '节点1-1-1', children: [] },
{ id: 5, name: '节点1-1-2', children: [] },
],
},
{ id: 3, name: '节点1-2', children: [] },
],
},
{
id: 6,
name: '节点2',
children: [
{ id: 7, name: '节点2-1', children: [] },
{ id: 8, name: '节点2-2', children: [] },
],
},
];
函数调用
提取所有节点的 id
和 name
属性:
const flatData = extractTree(treeData, 'children', ['id', 'name']);
console.log(flatData);
输出结果
[
{ id: 1, name: '节点1' },
{ id: 2, name: '节点1-1' },
{ id: 4, name: '节点1-1-1' },
{ id: 5, name: '节点1-1-2' },
{ id: 3, name: '节点1-2' },
{ id: 6, name: '节点2' },
{ id: 7, name: '节点2-1' },
{ id: 8, name: '节点2-2' }
];
实现细节
1. 函数逻辑
-
递归遍历树形结构:
- 每次处理当前节点时,提取指定的属性并添加到结果数组中。
- 如果当前节点存在子节点(通过
childs
字段判断),继续递归遍历其子节点。
-
属性过滤:
- 支持传入一个数组
attrArr
指定要提取的字段。 - 如果未指定,则默认提取当前节点的所有属性(不包括子节点字段)。
- 支持传入一个数组
2. 校验与容错
-
输入校验:
- 检查
arrs
是否为数组且非空,若条件不符直接返回空数组。 - 检查
childs
是否为字符串,确保能够正确找到子节点字段。
- 检查
-
属性处理:
- 当未指定提取的属性时,通过
Object.keys
获取节点的所有属性并移除子节点字段。
- 当未指定提取的属性时,通过
优化点
-
动态适配属性:
- 默认情况下提取节点的全部属性(不包括子节点字段),但支持用户自定义提取指定字段,灵活性高。
-
支持深层嵌套:
- 使用递归方式对树状结构的所有层级节点进行处理,适合任意深度的树形数据。
-
清晰模块化:
- 通过递归函数
flatten
分离了具体逻辑,使代码更具可读性和复用性。
- 通过递归函数
适用场景
-
前端列表渲染:
- 将多层树形数据转换为平铺数组,便于直接渲染为列表。
-
搜索与过滤:
- 扁平化后便于对树形数据进行全局搜索或按条件过滤。
-
统计与分析:
- 可快速统计树形结构中的所有节点或提取特定属性用于数据分析。
注意事项
-
树形数据格式要求:
- 数据需保证层级结构明确,且所有节点的子节点字段名一致(如
children
)。
- 数据需保证层级结构明确,且所有节点的子节点字段名一致(如
-
大规模数据处理:
- 对于层级深、节点多的树形数据,建议结合异步方法或优化递归以提升性能。
总结
此方法通过递归遍历和动态提取属性,实现了树形数据的高效扁平化处理,逻辑清晰、灵活性高,适用于前端多种业务场景。