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>