我们表明家族之间的父子关系可以有很多方式,常见的有两种,一种是较为形象的树型图,比如下面这种:
另一种是关系表,比如下图这种:
我们可以将上面两种形式在js分别定义为一个树型对象和数组:
//树形对象
const family = {
name:"曹操",
children:[
{
name:'曹植',
children:[
{
name:"曹光",
},
{
name:"曹满",
}
]
},
{
name:'曹丕',
children:[
{
name:"曹睿",
},
{
name:"曹言",
}
]
}
]
}
//关系表对应的数组
const list = [
{name:"曹操",parent:''},
{name:'曹植',parent:'曹操'},
{name:'曹丕',parent:'曹操'},
{name:'曹光',parent:'曹植'},
{name:'曹满',parent:'曹植'},
{name:'曹睿',parent:'曹丕'},
{name:'曹言',parent:'曹丕'}
]
问题是:在大多数情况下,表明关系的时候,我们拿到的大多数是关系表数组而不是第一种树形对象 (因为:一是关系表数组存贮起来只需要几行,而树形对象存贮起来需要很多行,并不方便,二是现实生活中一般不会有人给你画个树形图来表明关系吧,那样不方便,大多数情况下都是用的关系表,比较简便明了)
现在假设,后端给前端的返回数据就是个关系表数组而不是树形对象,而前端要渲染页面需要用到这个树形对象(例如elementUi中的树组件),那么我们如何将这个关系表数组转化为树形对象呢?
因为我们每个树形图的每一层关系都是父子,如果我们可以定义一个函数,这个函数可以返回父节点的所有子节点,那就方便了
function getChildrenList(List,name){
//list为关系表数组
//name为要查询子节点的父节点名
const res = []//定义name对应的所有子节点数组
//循环关系表数组,找到子节点
List.forEach(item=>{
//如果遍历到的对象item的父节点就是name的话,说明item就是name的子节点
if(item.parent === name){
//将子节点放入res中
res.push(item)
}
})
//循环完成之后返回子节点数组
return res
}
const result = getChildrenList(list,'曹操')
console.log(result)//[ { name: '曹植', parent: '曹操' }, { name: '曹丕', parent: '曹操' } ]
有了这个函数,我们可以查找到某个父节点下面的所有子节点,比如曹操的儿子是曹植和曹丕
现在我们只能找到父节点的子节点,并不能找到父节点的孙子节点(也就是子节点的子节点),那么如何找子节点的子节点呢,显然,我们让子节点作为父节点,再次调用这个找子节点的函数,就可以找到子节点的子节点了,依次类推,不断回调,一直找下去,直到某个节点再没有子节点停止,如下图所示:
代码如下:
function getChildrenList(List,name){
//list为关系表数组
//name为要查询子节点的父节点名
const res = []//定义name对应的所有子节点数组
//循环关系表数组,找到子节点
List.forEach(item=>{
//如果遍历到的对象item的父节点就是name的话,说明item就是name的子节点
if(item.parent === name){
//以item作为新的父节点,再次查找他的子节点
item.children=getChildrenList(List,item.name)
//将子节点放入res中
res.push(item)
}
})
//循环完成之后返回子节点数组
return res
}
const result = getChildrenList(list,'曹操')
console.log(result)
// [
// { name: '曹植', parent: '曹操', children: [ [Object], [Object] ] },
// { name: '曹丕', parent: '曹操', children: [ [Object], [Object] ] }
// ]
例如:以曹操作为父节点,我们查找到了他的子节点和他的子节点的子节点(孙子节点),这是一个数组,最后我们将曹操作为根节点,将这个数组作为他的children,拼装起来,就可以返回一个家族关系的树形对象了
function getChildrenList(List,name){
//list为关系表数组
//name为要查询子节点的父节点名
const res = []//定义name对应的所有子节点数组
//循环关系表数组,找到子节点
List.forEach(item=>{
//如果遍历到的对象item的父节点就是name的话,说明item就是name的子节点
if(item.parent === name){
//以item作为新的父节点,再次查找他的子节点
item.children=getChildrenList(List,item.name)
//将子节点放入res中
res.push(item)
}
})
//循环完成之后拼装,形成树形对象
return {
name:name,
children:res
}
}
const result = getChildrenList(list,'曹操')
console.log(result)
// {
// name: '曹操',
// children: [
// { name: '曹植', parent: '曹操', children: [Object] },
// { name: '曹丕', parent: '曹操', children: [Object] }
// ]
// }