前端数组生成树结构

98 阅读2分钟

在前端开发中,有个很常见的需求是需要生成一些树形结构的场景,往往是后端返回一个包含所有节点数组(好的后端会帮你生成树形结构),那么当后端不给我们生成怎没办呢?那咱们就得自食其力了。

下面给大家带来几种方法处理这种树形问题。

举个例子给大家演示一下:

const arr = [
  { id: 1, name: "部门1", pid: 0 },
  { id: 2, name: "部门2", pid: 1 },
  { id: 3, name: "部门3", pid: 1 },
  { id: 4, name: "部门4", pid: 3 },
  { id: 5, name: "部门5", pid: 0 },
  { id: 6, name: "部门6", pid: 5 },
];

/**
 * 生成树形结构方法一
 * 采用递归的方法实现
 * @param {Array} data 数据源
 * @param {Number} rootId 根节点id
 */
function generateTree1(data, rootId) {
  function getChildren(data, result = [], id) {
    for (let i = 0; i < data.length; i++) {
      if (data[i].pid === id) {
        data[i].children || (data[i].children = []);
        result.push(data[i]);
        getChildren(
          data.filter((it) => it.id !== data[i].id),
          data[i].children,
          data[i].id
        );
      }
    }
  }
  const result = [];
  getChildren(data, result, rootId);
  return result;
}

// console.log(generateTree1(arr, 0));

/**
 * 生成树形结构方法二
 * 采用数组自带的方法实现
 */
function generateTree2(data, rootId) {
  return data
    .filter((item) => item.pid === rootId)
    .map((item) => ({ ...item, children: generateTree2(data, item.id) }));
}
// console.log(generateTree2(arr, 0));

/**
 * 生成树形结构方法三
 * 采用reduce方法实现
 */
function generateTree3(data, rootId) {
  return data.reduce((result, item) => {
    if (item.pid === rootId) {
      item.children = generateTree3(data, item.id);
      result.push(item);
    }
    return result;
  }, []);
}
// console.log(generateTree3(arr, 0));

/**
 * 生成树形结构方法四
 * 不使用递归的方法实现
 */
function generateTree4(data, rootId) {
  const map = new Map();
  for (let i = 0; i < data.length; i++) {
    map.set(data[i].id, data[i]);
  }
  const result = [];
  for (let i = 0; i < data.length; i++) {
    if (data[i].pid === rootId) {
      result.push(data[i]);
    } else {
      const parent = map.get(data[i].pid);
      if (parent) {
        parent.children = parent.children || [];
        parent.children.push(data[i]);
      }
    }
  }
  return result;
}
console.log(generateTree4(arr, 0));

前三种方法本质上是递归的思想,只是运用了数组的不同方法。

总结

  • 递归方法:代码简洁,但在数据量较大时可能会有性能问题。
  • 迭代方法:性能较好,适合处理大量数据。
    1. 遍历数组,将每个元素转换为树节点,并用一个对象(或Map)来存储,以id为键,方便快速查找
    2. 再次遍历数组,根据每个元素的parentId找到其父节点,并将当前节点添加到父节点的children数组中。
    3. 确定根节点,通常是parentId为null、undefined、0或者特定值(比如0)的元素,然后将这些根节点收集起来作为树的顶层