最近搞得一个小需求,就是有个树形结构,然后知道里层其中一个id,我们要找到它所属的每层父级节点,当然也包括它自己。因为之前还真没搞过这种,然后就想了下,完美实现,然后也找到了一个第三方库。接下来说下我的思路和处理方式
先上个测试数据
const tree = [
{
id: '1',
parentId: 0,
name: '山东省',
children: [
{
id: '1-1',
parentId: '1',
name: '济南市',
children: [
{
id: '1-1-1',
parentId: '1-1',
name: '历下区',
children: []
},
{
id: '1-1-2',
parentId: '1-1',
name: '历城区',
children: []
}
]
},
{
id: '1-2',
parentId: '1',
name: '菏泽市',
children: [
{
id: '1-2-1',
parentId: '1-2',
name: '郓城县',
children: []
},
{
id: '1-2-2',
parentId: '1-2',
name: '鄄城县',
children: []
}
]
}
]
}
]
方式一: 自己处理
处理分为两步:
① 我会先将树形结构扁平化,处理为同级
② 遍历上面扁平后的的数据,先根据已知id找出第一个,然后再根据它的parentId再找,知道找到parentId为0(无上级)的为止,也是一个递归操作
然后下面贴上两个方法,分别对应上面的两步
// 1. 先将树形结构扁平化,处理为同级
flatTreeAndSetLevel(tree, level = 1) {
const list = []
tree.forEach(item => {
const o = JSON.parse(JSON.stringify(item))
if(o.children) delete o.children
o.level = level
list.push(o)
if(item.children && item.children.length) {
list.push(...this.flatTreeAndSetLevel(item.children, level + 1))
}
})
return list
}
// 2. 遍历上面扁平后的的数据,先根据id找出第一个,然后再根据它的parentId再找,知道找到parentId为0的为止,也是一个递归操作
function getParentAreas(pid, list) {
const target = []
const o = list.find(item => item.id == pid) || {}
if(JSON.stringify(o) != '{}') target.push(o)
if(o.parentId) target.push(...getParentAreas(o.parentId, list))
return target
}
接下来就是测试一下:
console.log(getParentAreas('1-1-2', flatTreeAndSetLevel(tree)), '----->>>')
// [
// { id: '1-1-2', parentId: '1-1', name: '历城区' },
// { id: '1-1', parentId: '1', name: '济南市' },
// { id: '1', parentId: 0, name: '山东省' }
// ]
因为是根据里面找的,所以找出来的是从里层带外层,如果想反过来,再reverse一下就可以了
然后可以将上面的代码进行优化,因为处理数据用到了两个方法,所以我这里把这两个方法写到一个类中,我们在实例化的时候就去执行上述方法,直接拿到我们所需要的数据
class FindArrsById {
constructor(id, tree) {
this.id = id
this.flatArr = this.flatTreeAndSetLevel.call(this, tree)
this.parentAreas = this.getParentAreas.call(this, this.id, this.flatArr)
this.getParentNames.bind(this)
}
flatTreeAndSetLevel(tree, level = 1) {
const list = []
tree.forEach(item => {
const o = JSON.parse(JSON.stringify(item))
if(o.children) delete o.children
o.level = level
list.push(o)
if(item.children && item.children.length) {
list.push(...this.flatTreeAndSetLevel(item.children, level + 1))
}
})
return list
}
getParentAreas(pid, list) {
const target = []
let o = list.find(item => item.id == pid) || {}
if(JSON.stringify(o) != '{}') target.push(o)
if(o.parentId) target.push(...this.getParentAreas(o.parentId, list))
return target
}
// 该方法就是拿到里面某个字段的集合
getParentNames() {
return this.parentAreas.map(item => item.name).reverse()
}
}
测试一下:
console.log(new FindArrsById('1-1-2', tree).getParentNames('name'), '----->>>')
// [ '山东省', '济南市', '历城区' ]
方式二:采用 xe-utils 第三方库
xe-utils GitHub地址https://github.com/x-extends/xe-utils
文档: https://vxetable.cn/xe-utils/#/
安装:
npm install xe-utils
使用:
const XEUtiles = require('xe-utils') // 或者使用ES6中的import都可以
let searchTree = XEUtiles.searchTree(tree, item => item.id == '1-1-2', { children: 'children' })
console.log(searchTree, '----->>>')
// [
// {
// id: '1',
// parentId: 0,
// name: '山东省',
// children: [
// {
// id: '1-1',
// parentId: '1',
// name: '济南市',
// children: [
// {
// id: '1-1-2',
// parentId: '1-1',
// name: '历城区',
// children: []
// }
// ]
// }
// ]
// }
// ]
这个还是个满强大的库,我其实没用这个,这是后来做完之后发现的,里面有很多很多的方法,各种数据、方法的转换操作,用的6的话确实蛮方便的 。
但是我一般的话还是自己能处理就处理了,不是太复杂的话,能不用就不用了。