概述
树形数据结构化即把扁平化的数据转化为树形结构,此操作在前端应用的场景有,处理vue中的路由权限,处理树形dom节点比如tree组件。
初始树形数据结构化
- 描述
有以下数据,如何将该数据转化为树形结构?
const data = [
{
id: 2,
pid: 0,
path: '/course',
name: 'Course',
title: '课程管理'
},
{
id: 3,
name: 'CourseOperate',
path: 'operate',
link: '/course/operate',
pid: 2,
title: '课程操作'
},
{
id: 4,
name: 'CourseInfoData',
path: 'info_data',
link: '/course/operate/info_data',
pid: 3,
title: '课程数据'
},
{
id: 5,
name: 'CourseAdd',
path: 'add',
link: '/course/add',
pid: 2,
title: '增加课程'
},
{
id: 6,
pid: 0,
path: '/student',
name: 'Student',
title: '学生管理',
},
{
id: 7,
name: 'StudentOperate',
path: 'operate',
link: '/student/operate',
pid: 6,
title: '学生操作'
},
{
id: 8,
name: 'StudentAdd',
path: 'add',
link: '/student/add',
pid: 6,
title: '增加学生'
},
{
id: 9,
name: '123123',
path: '234234',
link: '/student/add',
pid: 8,
title: '增加学生'
},
{
id: 10,
name: '234234',
path: '345345',
link: '/student/add',
pid: 9,
title: '增加学生'
},
{
id: 11,
name: '345345',
path: '456456',
link: '/student/add',
pid: 10,
title: '增加学生'
}
];
- 实现方案
将上面数据转化为树形结构数据需要找到标记父节点是谁的属性,此例中标记父节点是谁的属性是pid,根据该属性将pid值相同的一类对象放在一起存放到children数组中,同时将该数组放入到对应父节点的对象中。
此外需注意如何找到顶级节点:标记父节点的pid属性值在id中没有出现的那个对象即为顶级节点
- 实现代码
const data=[
{
id: 2,
pid: 0,
path: '/course',
name: 'Course',
title: '课程管理',
children: [
{
id: 3,
name: 'CourseOperate',
path: 'operate',
link: '/course/operate',
pid: 2,
title: '课程操作',
children: [
{
id: 4,
name: 'CourseInfoData',
path: 'info_data',
link: '/course/operate/info_data',
pid: 3,
title: '课程数据'
},
]
},
{
id: 5,
name: 'CourseAdd',
path: 'add',
link: '/course/add',
pid: 2,
title: '增加课程'
},
]
},
{
id: 6,
pid: 0,
path: '/student',
name: 'Student',
title: '学生管理',
children: [
id: 7,
name: 'StudentOperate',
path: 'operate',
link: '/student/operate',
pid: 6,
title: '学生操作'
},
{
id: 8,
name: 'StudentAdd',
path: 'add',
link: '/student/add',
pid: 6,
title: '增加学生',
children: [
{
id: 9,
name: '123123',
path: '234234',
link: '/student/add',
pid: 8,
title: '增加学生',
children: [
{
id: 10,
name: '234234',
path: '345345',
link: '/student/add',
pid: 9,
title: '增加学生',
children: [
{
id: 11,
name: '345345',
path: '456456',
link: '/student/add',
pid: 10,
title: '增加学生'
}
]
},
]
},
]
},
]
},
]
编写程序实现数据树形结构化
思路
一个扁平数据列表需要有描述树形结构的字段 PID,根据PID扁平化数据转化为树形数据列表,首先要找到顶级节点作为转化为树形结构数据突破口,即将顶级节点数据与子级节点数据分开。最后使用递归将扁平数据转化为树形数据结构。
实现
- 将顶级节点与子级节点数据分开
const data = [
{
id: 2,
pid: 0,
path: '/course',
name: 'Course',
title: '课程管理'
},
{
id: 3,
name: 'CourseOperate',
path: 'operate',
link: '/course/operate',
pid: 2,
title: '课程操作'
},
{
id: 4,
name: 'CourseInfoData',
path: 'info_data',
link: '/course/operate/info_data',
pid: 3,
title: '课程数据'
},
{
id: 5,
name: 'CourseAdd',
path: 'add',
link: '/course/add',
pid: 2,
title: '增加课程'
},
{
id: 6,
pid: 0,
path: '/student',
name: 'Student',
title: '学生管理',
},
{
id: 7,
name: 'StudentOperate',
path: 'operate',
link: '/student/operate',
pid: 6,
title: '学生操作'
},
{
id: 8,
name: 'StudentAdd',
path: 'add',
link: '/student/add',
pid: 6,
title: '增加学生'
},
{
id: 9,
name: '123123',
path: '234234',
link: '/student/add',
pid: 8,
title: '增加学生'
},
{
id: 10,
name: '234234',
path: '345345',
link: '/student/add',
pid: 9,
title: '增加学生'
},
{
id: 11,
name: '345345',
path: '456456',
link: '/student/add',
pid: 10,
title: '增加学生'
}
];
function filterParentandChildren(data) {
let parents = data.filter(p => p.pid === 0)
let children = data.filter(c => c.pid !== 0)
handleChildren(parents, children)
console.log(parents)
console.log(children)
}
function handleChildren(parents, children) {
parents.map(p => {
children.map(c => {
if (p.id === c.pid) {
if (p.children) {
p.children.push(c)
} else {
p.children = [c]
}
}
})
})
}
filterParentandChildren(data)
- 添加递归实现树形结构化
const data = [
{
id: 2,
pid: 0,
path: '/course',
name: 'Course',
title: '课程管理'
},
{
id: 3,
name: 'CourseOperate',
path: 'operate',
link: '/course/operate',
pid: 2,
title: '课程操作'
},
{
id: 4,
name: 'CourseInfoData',
path: 'info_data',
link: '/course/operate/info_data',
pid: 3,
title: '课程数据'
},
{
id: 5,
name: 'CourseAdd',
path: 'add',
link: '/course/add',
pid: 2,
title: '增加课程'
},
{
id: 6,
pid: 0,
path: '/student',
name: 'Student',
title: '学生管理',
},
{
id: 7,
name: 'StudentOperate',
path: 'operate',
link: '/student/operate',
pid: 6,
title: '学生操作'
},
{
id: 8,
name: 'StudentAdd',
path: 'add',
link: '/student/add',
pid: 6,
title: '增加学生'
},
{
id: 9,
name: '123123',
path: '234234',
link: '/student/add',
pid: 8,
title: '增加学生'
},
{
id: 10,
name: '234234',
path: '345345',
link: '/student/add',
pid: 9,
title: '增加学生'
},
{
id: 11,
name: '345345',
path: '456456',
link: '/student/add',
pid: 10,
title: '增加学生'
}
];
function filterParentandChildren(data) {
let parents = data.filter(p => p.pid === 0)
let children = data.filter(c => c.pid !== 0)
handleChildren(parents, children)
return parents
}
function handleChildren(parents, children) {
parents.map(p => {
children.map((c,i) => {
if (p.id === c.pid) {
let _children=JSON.parse(JSON.stringify(children))
_children.splice(i,1)
handleChildren([c],_children)
if (p.children) {
p.children.push(c)
} else {
p.children = [c]
}
}
})
})
}
const parents= filterParentandChildren(data)
console.log(parents)
拓展:使用扁平化的思路处理树形结构
- 概述
遍历数组每一项,每次循环再次遍历数组每一项,将每一项节点的子节点筛选出来放入每一项的children中,最后返回顶级节点的筛选项。 - 实现代码
function handleTreeData(data){
let _data=JSON.parse(JSON.stringify(data))
_data.filter(p=>{
let arr=_data.filter(c=>p.id===c.pid)
arr.length && (_data.children=arr)
return p.pid===0
})
}
handleTreeData(data)