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>
相关推荐
_志哥_5 分钟前
解除有些网站不能复制的终极办法
前端·chrome
愚昧之山绝望之谷开悟之坡20 分钟前
什么是uv和传统的区别
前端·chrome·uv
SRC_BLUE_1729 分钟前
NSSCTF - Web | 【第五空间 2021】pklovecloud
android·前端
golang学习记30 分钟前
从0死磕全栈之Next.js 数据安全实战指南:从零信任到安全架构
前端
云中雾丽32 分钟前
flutter中 getx 的使用
前端
Jay丶1 小时前
聊聊入职新公司两个月,试用期没过这件事
前端·面试
ZTeam前端全栈进阶圈1 小时前
Vue新技巧:<style>标签里的 CSS 也能响应式!
前端
ღ_23331 小时前
vue3二次封装element-plus表格,slot透传,动态slot。
前端·javascript·vue.js
摸着石头过河的石头1 小时前
JavaScript继承的多种实现方式详解
前端·javascript
ybb_ymm1 小时前
前端开发之ps基本使用
前端·css