js树形结构,根据里层id找出它所属的每层父级集合

最近搞得一个小需求,就是有个树形结构,然后知道里层其中一个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的话确实蛮方便的 。

但是我一般的话还是自己能处理就处理了,不是太复杂的话,能不用就不用了。

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

会说法语的猪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值