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. 思路

首先,这里parentId为null的是一级父节点,然后其他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>
相关推荐
架构技术专栏23 分钟前
Agent 工具调用:从工具声明到执行反馈
前端·人工智能·后端
别动我齐刘海1 小时前
C++ 工程化学习
java·linux·前端·c++·学习·机器学习·机器人
志尊宝2 小时前
Vue3 零基础每日笔记(071):暗黑模式与主题切换——CSS 变量 + Element Plus 暗黑方案
前端·css·笔记·vue·html·前端开发·软件开发
WeiXin_DZbishe2 小时前
基于springboot城市公交实时运营与调度系统-计算机毕设 附源码【课程设计】66173
java·vue.js·spring boot·后端·python·php·课程设计
刘发财2 小时前
前端如何生成10000页PDF文件?
前端·javascript·开源
WeiXin_DZbishe3 小时前
基于Springboot+AI的kuall音乐广场的设计与实现-计算机毕设 附源码【课程设计】12715
vue.js·人工智能·spring boot·后端·python·php·课程设计
A接拉起0073 小时前
2026 年 JavaScript 开发者需要了解的知识
前端·javascript·后端
_馒头3 小时前
pixiJs游戏开发实践 - 跳棋小游戏
javascript·vue.js
用户11481867894843 小时前
面试官:大屏项目里十几个模块同时渲染上万条数据,怎么做到不卡?
前端·性能优化
前端市界3 小时前
Pro React Admin: 统一工程底座,承载多种应用...
前端·github