每天一点前端知识 - 数组转为树

64 阅读1分钟

实现

const arr2Tree =
  fn =>
    (arr, idKey = 'id', childKey = 'children', treeRoot = -1) => {
      if (!Array.isArray(arr)) {
        return arr;
      }
      const tmpData = {};
      const keys = arr.map(v => v[idKey]);
      [...arr].map(v => {
        const item = {...v};
        const {[idKey]: id} = item;
        if (id != null) {
          let {parentId} = item;
          if (parentId == null) {
            parentId = fn?.(item) ?? treeRoot;
            item.parentId = parentId;
          }
          if (!tmpData[id]) {
            tmpData[id] = [];
          }
          item[childKey] = tmpData[id];
          if (!tmpData[parentId]) {
            tmpData[parentId] = [];
          }
          if (!tmpData[treeRoot]) {
            tmpData[treeRoot] = [];
          }
          const hasParent = keys.includes(parentId);
          if (hasParent) {
            tmpData[parentId].push(item);
          } else {
            tmpData[treeRoot].push(item);
          }
        }
      });
      return tmpData[treeRoot];
    };

  • fn:回调函数
  • arr:数组
  • idKey:节点 ID key
  • childKey:子节点 key
  • treeRoot:根节点

这是一个高阶函数,传入的 fn 函数可以自定义处理当前节点 parentId

例如:由此高阶函数可以定义一个通过 path 地址自动将路由数组转为路由树结构的函数。

const arr2TreeByPath = (data, idKey = 'path', childKey = 'children', treeRoot = null) =>
  arr2Tree(item => {
    const id = item[idKey];
    const hasSub = id.match(/.*\/[^:/]+\/:[^/]+/);
    if (hasSub) {
      return hasSub[0].match(/(.*)\/:+/)?.[1] ?? treeRoot;
    } else {
      return id.match(/(.*)\/+/)?.[1] ?? treeRoot;
    }
  })(data, idKey, childKey, treeRoot);

示例

const arr = [
  {
    parentId: '-1',
    id: '0',
    name: '0',
  },
  {
    parentId: '0',
    id: '01',
    name: '01',
  },
  {
    parentId: '-1',
    id: '2',
    name: '2',
  },
  {
    parentId:'0',
    id: '03',
    name: '03',
  },
  {
    parentId: '1',
    id: '11',
    name: '11',
  },
  {
    parentId: '2',
    id: '21',
    name: '21',
  },
  {
    parentId: '-1',
    id: '1',
    name: '1',
  },
  {
    parentId: '2',
    id: '22',
    name: '22',
  },
  {
    parentId: '0',
    id: '02',
    name: '02',
  },
  {
    parentId: '1',
    id: '12',
    name: '12',
  },
  {
    parentId: '21',
    id: '211',
    name: '211',
  },
];
const arr1 = [
  {
    path: '/a',
    name: 'a',
  },
  {
    path: '/a/1',
    name: 'a1',
  },
  {
    path: '/c',
    name: 'c',
  },
  {
    path: '/a/3',
    name: 'a3',
  },
  {
    path: '/b/1',
    name: 'b1',
  },
  {
    path: '/c/1',
    name: 'c1',
  },
  {
    path: '/b',
    name: 'b',
  },
  {
    path: '/c/2',
    name: 'c2',
  },
  {
    path: '/a/2',
    name: 'a2',
  },
  {
    path: '/b/2',
    name: 'b2',
  },
  {
    path: '/b/1/1',
    name: 'b11',
  },
];

arr2Tree()(arr);

arr2TreeByPath(arr1);

3.png

3-result.png

演示地址:ihuxy.com/play?utils=…