树结构扁平化方法

功能概述

通过递归遍历树状结构数据,将其转换为扁平化的数组,同时支持提取指定的公共属性。
常用于将多层级的树形数据结构变为单层数组,便于后续操作(如列表渲染、查找等)。


核心代码

函数实现

/**
 * @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: [] },
    ],
  },
];

函数调用

提取所有节点的 idname 属性:

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 获取节点的所有属性并移除子节点字段。

优化点

  1. 动态适配属性

    • 默认情况下提取节点的全部属性(不包括子节点字段),但支持用户自定义提取指定字段,灵活性高。
  2. 支持深层嵌套

    • 使用递归方式对树状结构的所有层级节点进行处理,适合任意深度的树形数据。
  3. 清晰模块化

    • 通过递归函数 flatten 分离了具体逻辑,使代码更具可读性和复用性。

适用场景

  1. 前端列表渲染

    • 将多层树形数据转换为平铺数组,便于直接渲染为列表。
  2. 搜索与过滤

    • 扁平化后便于对树形数据进行全局搜索或按条件过滤。
  3. 统计与分析

    • 可快速统计树形结构中的所有节点或提取特定属性用于数据分析。

注意事项

  1. 树形数据格式要求

    • 数据需保证层级结构明确,且所有节点的子节点字段名一致(如 children)。
  2. 大规模数据处理

    • 对于层级深、节点多的树形数据,建议结合异步方法或优化递归以提升性能。

总结

此方法通过递归遍历和动态提取属性,实现了树形数据的高效扁平化处理,逻辑清晰、灵活性高,适用于前端多种业务场景。