Vue将后端数据转成树形结构的方法

1. 前言

需要将后端传来的数据转成嵌套的树形结构,后端数据形式如下:

json 复制代码
[
  {
    "id": 48,
    "parentId": 47,
    "workspaceName": "工艺计划书合集",
    "workspaceCode": "A8-B1"
  },
  {
    "id": 47,
    "parentId": null,
    "workspaceName": "工艺计划书",
    "workspaceCode": "A8"
  },
  {
    "id": 26,
    "parentId": null,
    "workspaceName": "0501DKD工作指导书",
    "workspaceCode": "A2"
  },
  {
    "id": 29,
    "parentId": 26,
    "workspaceName": "月度计划工艺包装方案A",
    "workspaceCode": "A2-B1"
  },
  {
    "id": 35,
    "parentId": 26,
    "workspaceName": "月度计划工艺包装方案B",
    "workspaceCode": "A2-B2"
  }
]

2. 思路

首先,这里parentIdnull的是一级父节点,然后其他parentId有值的挂在对应id节点之后,最后整理的结果应该是这样一个效果:

json 复制代码
[
  {
    "id": 47,
    "parentId": null,
    "workspaceName": "工艺计划书",
    "workspaceCode": "A8",
    "children": {
      "id": 48,
      "parentId": 47,
      "workspaceName": "工艺计划书合集",
      "workspaceCode": "A8-B1"
    }
  },
  {
    "id": 26,
    "parentId": null,
    "workspaceName": "0501DKD工作指导书",
    "workspaceCode": "A2",
    "children": [
      {
        "id": 29,
        "parentId": 26,
        "workspaceName": "月度计划工艺包装方案A",
        "workspaceCode": "A2-B1"
      },
      {
        "id": 35,
        "parentId": 26,
        "workspaceName": "月度计划工艺包装方案B",
        "workspaceCode": "A2-B2"
      }
    ]
  }
]

3. 代码

第一种是使用ES6的map语法:

javascript 复制代码
function listToTree(data) {
  const map = new Map();
  const tree = [];

  // 第一步:遍历数据,将每一项存入 Map 中,并初始化 children = []
  data.forEach((p) => {
    p.children = [];
    // 将节点的 id 作为 key,整个节点对象作为 value 存入 Map
    map.set(p.id, p);
  });

  // 第二步:再遍历一次数据,根据 parentId 找到父节点,并将当前节点加入父节点的 children
  data.forEach((p) => {
    // 找到父节点,把当前节点挂载为其子节点
    // 注意由于 map 中的值为一个对象,属于引用数据类型,所以这里处理 map,就可以实现 tree 中出现相应的嵌套数据
    if (p.parentId !== null && map.has(p.parentId)) {
      map.get(p.parentId).children.push(p);
    } else {
      // 如果 parentId 为 null 或找不到父节点,则是顶级节点,加入 tree 根节点数组
      tree.push(p);
    }
  });

  return tree;
}

第二种是若依框架的兼容IE浏览器的写法:

javascript 复制代码
/**
 * 构造树型结构数据
 * @param {*} data 数据源
 * @param {*} id id字段 默认 'id'
 * @param {*} parentId 父节点字段 默认 'parentId'
 * @param {*} children 孩子节点字段 默认 'children'
 */
export function handleTree(data, id, parentId, children) {
  let config = {
    id: id || 'id',
    parentId: parentId || 'parentId',
    childrenList: children || 'children',
  };

  var childrenListMap = {};
  var nodeIds = {};
  var tree = [];

  for (let d of data) {
    let parentId = d[config.parentId];
    if (childrenListMap[parentId] == null) {
      childrenListMap[parentId] = [];
    }
    nodeIds[d[config.id]] = d;
    childrenListMap[parentId].push(d);
  }

  for (let d of data) {
    let parentId = d[config.parentId];
    if (nodeIds[parentId] == null) {
      tree.push(d);
    }
  }

  for (let t of tree) {
    adaptToChildrenList(t);
  }

  function adaptToChildrenList(o) {
    if (childrenListMap[o[config.id]] !== null) {
      o[config.childrenList] = childrenListMap[o[config.id]];
    }
    if (o[config.childrenList]) {
      for (let c of o[config.childrenList]) {
        adaptToChildrenList(c);
      }
    }
  }
  return tree;
}

4. 完整演示Demo

html 复制代码
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Document</title>
</head>

<body></body>

<script>
  const data = [
    {
      id: 48,
      parentId: 47,
      workspaceName: '工艺计划书合集',
      workspaceCode: 'A8-B1',
    },
    {
      id: 47,
      parentId: null,
      workspaceName: '工艺计划书',
      workspaceCode: 'A8',
    },
    {
      id: 26,
      parentId: null,
      workspaceName: '0501DKD工作指导书',
      workspaceCode: 'A2',
    },
    {
      id: 29,
      parentId: 26,
      workspaceName: '月度计划工艺包装方案A',
      workspaceCode: 'A2-B1',
    },
    {
      id: 35,
      parentId: 26,
      workspaceName: '月度计划工艺包装方案B',
      workspaceCode: 'A2-B2',
    },
  ];

  function listToTree(data) {
    const map = new Map();
    const tree = [];

    data.forEach((p) => {
      p.children = [];
      map.set(p.id, p);
    });

    data.forEach((p) => {
      if (p.parentId !== null && map.has(p.parentId)) {
        map.get(p.parentId).children.push(p);
      } else {
        tree.push(p);
      }
    });

    return tree;
  }

  const result = listToTree(data);

  console.log('result:', result);
</script>

</html>
相关推荐
小满zs3 小时前
Zustand 第五章(订阅)
前端·react.js
涵信4 小时前
第一节 基础核心概念-TypeScript与JavaScript的核心区别
前端·javascript·typescript
谢尔登4 小时前
【React】常用的状态管理库比对
前端·spring·react.js
编程乐学(Arfan开发工程师)4 小时前
56、原生组件注入-原生注解与Spring方式注入
java·前端·后端·spring·tensorflow·bug·lua
小公主5 小时前
JavaScript 柯里化完全指南:闭包 + 手写 curry,一步步拆解原理
前端·javascript
姑苏洛言6 小时前
如何解决答题小程序大小超过2M的问题
前端
GISer_Jing7 小时前
JWT授权token前端存储策略
前端·javascript·面试
开开心心就好7 小时前
电脑扩展屏幕工具
java·开发语言·前端·电脑·php·excel·batch
拉不动的猪7 小时前
es6常见数组、对象中的整合与拆解
前端·javascript·面试
GISer_Jing8 小时前
Vue Router知识框架以及面试高频问题详解
前端·vue.js·面试