本文层级化数组的方法借鉴于这位大佬的博客:JavaScript 层级数组常用工具方法(一)—— 数组结构转换_js对象数组转换成4层结构的递归算法-CSDN博客
一、题目:
let arr = [
{ id: 1, father_id: 0, status: 1, name: '数学学院' },
{ id: 2, father_id: 1, status: 1, name: '统计专业' },
{ id: 3, father_id: 2, status: 1, name: '线性代数' },
{ id: 7, father_id: 1, status: 1, name: '应用数学' },
{ id: 8, father_id: 7, status: 1, name: '概率论' },
{ id: 9, father_id: 7, status: 1, name: '微积分应用' },
{ id: 10, father_id: 7, status: 1, name: '运筹学' },
{ id: 11, father_id: 7, status: 1, name: '高等数学' },
{ id: 71, father_id: 1, status: 1, name: '计算专业' },
{ id: 56, father_id: 0, status: 1, name: '信息工程学院' },
{ id: 57, father_id: 56, status: 1, name: '计算结科学与技术' },
{ id: 58, father_id: 56, status: 1, name: '物联网' }
]
请你通过JS函数将以上数据转化为层级结构,如下
[
{
"id":1,
"parentId":0,
"isEnabled":true,
"name":"数学学院",
"_child":[
{
"id":2,
"parentId":1,
"isEnabled":true,
"name":"统计专业",
"_child":[
{
"id":3,
"parentId":2,
"isEnabled":true,
"name":"线性代数"
}
]
},
{
"id":7,
"parentId":1,
"isEnabled":true,
"name":"应用数学",
"_child":[
{
"id":8,
"parentId":7,
"isEnabled":true,
"name":"概率论"
},
{
"id":9,
"parentId":7,
"isEnabled":true,
"name":"微积分应用"
},
{
"id":10,
"parentId":7,
"isEnabled":true,
"name":"运筹学"
},
{
"id":11,
"parentId":7,
"isEnabled":true,
"name":"高等数学"
}
]
},
{
"id":71,
"parentId":1,
"isEnabled":true,
"name":"计算专业"
}
]
},
{
"id":56,
"parentId":0,
"isEnabled":true,
"name":"信息工程学院",
"_child":[
{
"id":57,
"parentId":56,
"isEnabled":false,
"name":"计算结科学与技术"
},
{
"id":58,
"parentId":56,
"isEnabled":false,
"name":"物联网"
}
]
}
]
二、基础数组转化为层级结构数组的方法
方法1:Map
Map概述
Map 对象是键值对的集合,并且能够记住键的原始插入顺序。
任何值(对象或者基本类型)都可以作为一个键或一个值,Map 中的一个键只能出现一次。
Map中get()和set()的使用方法
// 创建一个空的 Map
let myMap = new Map();
// 设置键值对
myMap.set('key1', 'value1');
myMap.set('key2', 'value2');
// 获取值
console.log(myMap.get('key1')); // 输出: value1
// 检查是否包含某个键
console.log(myMap.has('key2')); // 输出: true
解决问题
function convertToHierarchy(arr) {
const map = new Map(); // 使用 Map 存储每个对象,以便通过父ID快速查找
const result = [];
// 将每个对象存储到 Map 中
arr.forEach(item => {
//判断是否找到有孩子的对象
let flag = false;
arr.forEach(element => {
if (item.id === element.father_id) {
//找到有孩子的对象
flag = true;
}
if (flag) {
//初始化有孩子的层级
map.set(item.id, { ...item, _child: [] });
//找到一个就返回
return;
}
})
//遍历完发现没有找到
if (!flag) {
//将每个对象的id作为键,剩余内容作为值存储
map.set(item.id, { ...item });
}
});
// 构建层级结构
map.forEach(item => {
//item为map的值
if (item.father_id === 0) {
result.push(item); // 如果父ID为0,则为顶级对象
// console.log(result);
} else {
//根据父亲id获取父亲对象的值
const parent = map.get(item.father_id);
// console.log(parent);
//如果对象存在
if (parent) {
parent._child.push(item); // 将子对象添加到父对象的_child数组中
// console.log(result);
}
}
});
return result;
}
//将转换后的层级结构数组转换为 JSON 字符串,并使用 4 个空格进行缩进,最后输出结果。
// 第二个参数 null 是可选的 replacer 函数,用于选择性地替换对象的值,我们这里不需要进行替换,所以传入了 null。
console.log(JSON.stringify(convertToHierarchy(arr), null, 4));
方法2:递归1
优点:简单
缺点:无论有或没有子节点,都会有_child属性
function convertToHierarchyRecursively(data, parentId = 0) {
const result = [];
for (const item of data) {
//判断是否找到了当前 parentId 下的子节点
if (item.father_id === parentId) {
const newItem = { ...item, _child: convertToHierarchyRecursively(data, item.id) };
//将构建好的 newItem 对象添加到 result 数组中,表示成功找到并处理了当前 parentId 下的子节点
result.push(newItem);
}
}
return result;
}
// 使用示例
const hierarchyData = convertToHierarchyRecursively(arr);
console.log(JSON.stringify(hierarchyData, null, 2));
方法3:递归2
缺点:不灵活
function convertToHierarchy(flatArray, parentId) {
let hierarchy = [];
for (let item of flatArray) {
if (item.father_id === parentId) {
let newItem = {
id: item.id,
parentId: item.father_id,
isEnabled: item.status === 1,
name: item.name
};
let children = convertToHierarchy(flatArray, item.id);
if (children.length > 0) {
newItem._child = children;
}
hierarchy.push(newItem);
}
}
return hierarchy;
}
let hierarchicalData = convertToHierarchy(flatData, 0);
console.log(JSON.stringify(hierarchicalData, null, 4));
方法4:reduce
function convertToHierarchyWithReduce(arr) {
//item当前对象 result处理后的每次循环对象
return arr.reduce((result, item) => {
const newItem = { ...item, _child: [] };
//在 result 数组中查找是否存在 father_id 等于当前 item 的 id 的父节点。
const parent = result.find(parentItem => parentItem.id === item.father_id);
if (parent) {
parent._child.push(newItem);
} else {
result.push(newItem);
}
return result;
}, []);
}
// 使用示例
const hierarchyData = convertToHierarchyWithReduce(arr);
console.log(JSON.stringify(hierarchyData, null, 2));
三、借助上方思想用vue实现层级菜单
如下图
递归组件
递归组件是指在组件内部调用自身的一种组件设计模式。使用递归组件可以根据数据结构去动态渲染嵌套内容,例如树形结构、评论系统等。