树结构大家应该都比较熟悉,这里我主要说两种:一个根节点和多个根节点。一个根节点,就像我们的html节点,不可能有和它同级的;多个根节点,比如我们的一二级导航栏。下面一个个分析:
一个根节点
初级 - 只能是两层树
let arr = [
{
menuId: 1,
name: '系统1',
parentMenu: null
},
{
menuId: 2,
name: '系统1_0',
parentMenu: 1
},
{
menuId: 3,
name: '系统1_1',
parentMenu: 1
}
]
function turnToTreeOfOneRoot(arr) {
if (!Array.isArray(arr)) {
throw new Error('is not array')
} else {
return arr.reduce((cur, item) => {
if (item.parentMenu == null) {
cur = { children: [], ...item }
} else if (item.parentMenu == cur.menuId) {
cur.children.push(item)
}
return cur
}, {})
}
}
turnToTreeOfOneRoot(arr)
升级 - 随便几层
var arr1 = [
{
menuId: 1,
name: '系统管理1',
parentMenu: null
},
{
menuId: 2,
name: '系统管理1_0',
parentMenu: 1
},
{
menuId: 3,
name: '系统管理1_1',
parentMenu: 1
},
{
menuId: 4,
name: '系统管理2_0',
parentMenu: 2
}
]
function turnToTreeOfOneRootPlus(arr) {
var obj = {}
arr.forEach(item => {
if (item.parentMenu == null) {
obj = item
}
})
return arr.reduce((h, m) => {
// 如果不是根节点
if (m.parentMenu) {
foo(h, m)
}
// 在obj里面为cur找到归宿
function foo(obj, cur) {
if (obj.menuId === cur.parentMenu) {
if (!obj.children) {
obj.children = []
}
obj.children.push(cur)
} else if (obj.children) {
obj.children.forEach(item => {
foo(item, cur)
})
}
}
return h
}, obj)
}
turnToTreeOfOneRootPlus(arr1)
多个根节点
初级 - 只能是两层树
let arr2 = [
{
menuId: 1,
name: '系统1',
parentMenu: null
},
{
menuId: 2,
name: '系统1_0',
parentMenu: 1
},
{
menuId: 3,
name: '系统1_1',
parentMenu: 1
},
{
menuId: 4,
name: '系统2',
parentMenu: null
},
{
menuId: 5,
name: '系统4_0',
parentMenu: 4
}
]
function turnToTreeOfManyRoot(arr) {
if (!Array.isArray(arr)) {
throw new Error('is not array')
} else {
var roots = []
arr.forEach(item => {
if (item.parentMenu == null) {
item.children = []
roots.push(item)
}
})
return arr.reduce((roots, cur) => {
roots.forEach(item => {
// 如果是根节点
if (item.menuId == cur.parentMenu) {
item.children.push(cur)
}
})
return roots
}, roots)
}
}
turnToTreeOfManyRoot(arr2)
升级 - 随便几层
var arr3 = [
{
menuId: 1,
name: '系统管理1',
parentMenu: null
},
{
menuId: 2,
name: '系统管理2',
parentMenu: null
},
{
menuId: 3,
name: '系统管理1_0',
parentMenu: 1
},
{
menuId: 4,
name: '系统管理1_1',
parentMenu: 1
},
{
menuId: 5,
name: '系统管理2_0',
parentMenu: 2
},
{
menuId: 6,
name: '系统管理5_0',
parentMenu: 5
},
{
menuId: 7,
name: '系统管理3',
parentMenu: null
}
]
function turnToTreeOfManyRootPlus(arr) {
var arrs = []
arr.forEach(item => {
if (!item.parentMenu) {
arrs.push(item)
}
})
return arr.reduce((h, m) => {
if (m.parentMenu) {
foo(h, m)
}
function foo(arr, cur) {
arr.forEach(item => {
if (item.menuId === cur.parentMenu) {
if (!item.children) {
item.children = []
}
item.children.push(cur)
} else if (item.children) {
foo(item.children, cur)
}
})
}
return h
}, arrs)
}
turnToTreeOfManyRootPlus(arr3)
ps:最后提醒一下,数组里面的对象一定是排序过的,也就是说父级一定在前面,它的子级一定在后面。比如:
let arr = [
{
menuId: 1,
name: '系统1',
parentMenu: null
},
{
menuId: 4,
name: '系统2_0',
parentMenu: 2
},
{
menuId: 2,
name: '系统1_0',
parentMenu: 1
},
{
menuId: 3,
name: '系统1_1',
parentMenu: 1
}
]
这样的数组,会导致menuId: 4
丢失。因为它的父级在后面,所以遍历到它时没办法塞给它的父级。谨记:一定要排好序,然后进行数组遍历