递归清除树形结构中所有无叶子节点的子节点

433 阅读1分钟

需求: 多层级分组下只有一个图层,删除该图层后删除其所有无图层的祖先分组。 具体见下图。

image.png image.png

树形数据结构, 去除多余属性后结构如下: <其中分组id均以 group_开头>

[
  {
    "name": "分组",
    "id": "group_1672303062151",   
    "title": "分组",
    "modules": [
      {
        "name": "定制标题",        
        "id": "1608381678943666178"
      },
      {
        "name": "分组",
        "id": "group_1672303792251",
        "title": "分组",
        "modules": [
          {
            "name": "分组",
            "id": "group_1672303794937",
            "title": "分组",
            "modules": [
              {
                "name": "分组",
                "id": "group_1672303798174",
                "title": "分组",
                "modules": [
                  {
                    "name": "A",
                    "id": "1608382207992201218"
                  }
                ]
              }
            ]
          }
        ]
      }
    ]
  }
]

代码实现

export const filterEmptyGroups = (tree) => {
  const recursiveFn = (tree) => {
    for (let i = 0; i < tree.length; i++) {
      const item = tree[i];
      if (item.modules && Array.isArray(item.modules) && item.modules.length) {
        recursiveFn(item.modules);
      }
      if (item.id.startsWith("group") && item.modules.length === 0) {
        tree.splice(i, 1);
        // splice后,不将i--的话,会跳过数组中的项
        i--;
      }
    }
  };
  recursiveFn(tree);
  // 此时引用类型tree已经被改变了,所有引用它的地方都会改变,如果想避免这个问题, 可以将tree深拷贝一份儿再传进来
  return tree;
};

下面是最开始写的方法,后来review代码时候,回想了半天,愣是想不起来当时为啥子这样做了(应该不止我一个人有这种情况吧😂):在能拿到x.modules的情况下,还为了获取x.modules而把x传入recursiveFn,着实有点蠢了,哈哈。但是这种憨憨行为值得一记,毕竟很久以后回看的话定会哈哈一笑。

const filterEmptyGroups = tree => {
  //递归函数, par为当前
  const recursiveFn = (tree, par) => {
    tree.forEach((x, i) => {
      // 如果modules不为空数组,递归执行
      if (x.modules && Array.isArray(x.modules) && x.modules.length) {
        recursiveFn(x.modules, x);
      }
      if (x.id.startsWith("group") && x.modules.length === 0) {
        if (par.modules && par.modules.length) {
          par.modules.splice(i, 1);
        }
      }
    });
  };
  recursiveFn(tree, []);
  // 执行结束后最外面一层如果为分组的话是删除不到的,所以再过滤一次以去除最外层的空分组
  const finalTree = tree.filter((item) =>
    item.id.startsWith("group")
      ? Array.isArray(item.modules) && item.modules.length
      : true
  );
  return finalTree;
};