精讲 几种转树形结构方法

1,378 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第9天,点击查看活动详情

大家好,我是大帅子,今天给大家讲一下,我们后端返回的数据是一个平面结构的话,我们怎么转换为树形结构呢, 其实方法很多样, 今天就给大家讲一下其中的三种吧, 三种常用的,大家喜欢那个就用哪个吧~,嘿嘿,这么贴心的博主,还不都给小心心点起来~~~


介绍

我们先来看下面的数据吧

    let arr = [
      { 'id': '29', 'pid': '', 'name': '总裁办' },
      { 'id': '2c', 'pid': '', 'name': '财务部' },
      { 'id': '2d', 'pid': '2c', 'name': '财务核算部' },
      { 'id': '2f', 'pid': '2c', 'name': '薪资管理部' },
      { 'id': 'd2', 'pid': '', 'name': '技术部' },
      { 'id': 'd3', 'pid': 'd2', 'name': 'Java研发部' }
    ]
  • 这个是我们常从后端那,拿到的数据,我们观察一下数据
  • 我们 的一级 的pid值是空值
  • 我们的子级 的 pid值是父级的id值

OK 分析跟需求我就跟大家说到这里,这里,大家有什么思路吗 ? 可以尝试的写一下,然后回来再看一下我的方法,

1. 下包

没有什么是下包解决不了的,如果有的话,我们就 double , array-to-tree

步骤我带着大家可以看一下
  1. 下包
npm install array-to-tree --save

yarn add  array-to-tree 
  1. 里面有两种数据内容的数据 大家可以观察一下我们的数据更适合那种?

   var dataOne = [
     {
       id1,
       name: 'Portfolio',
       parent_id: undefined
     },
     {
       id2,
       name: 'Web Development',
       parent_id: 1
     },
     {
       id3,
       name: 'Recent Works',
       parent_id: 2
     },
     {
       id4,
       name: 'About Me',
       parent_id: undefined
     }
   ];



   var dataTwo = [
     {
       _id'ec654ec1-7f8f-11e3-ae96-b385f4bc450c',
       name: 'Portfolio',
       parent: null
     },
     {
       _id'ec666030-7f8f-11e3-ae96-0123456789ab',
       name: 'Web Development',
       parent: 'ec654ec1-7f8f-11e3-ae96-b385f4bc450c'
     },
     {
       _id'ec66fc70-7f8f-11e3-ae96-000000000000',
       name: 'Recent Works',
       parent: 'ec666030-7f8f-11e3-ae96-0123456789ab'
     },
     {
       _id'32a4fbed-676d-47f9-a321-cb2f267e2918',
       name: 'About Me',
       parent: null
     }
   ];

  1. 这里很显然是第二种

image.png

  1. 那我们就跟着第二种方法走
    // 1. 导包 
    import arrayToTree from 'array-to-tree'
    
    // 2. 可以定义一个工具函数
    export function getTree(arr){
        arrayToTree(arr, {
          parentProperty'pid',
          customID'id'
        })
    }
    
    // 3. 使用  搞定
    import {getTree} from '路径'
    
    getTree(arr)
    

2. 递归

这应该是我们第一时间该想到的, 是吧,因为我们的子组件可能会嵌套很多层, 所以我们就要用递归来搞

  1. 分析一下 我们可以什么都不用想 直接先定义一个函数
function getTree (){
    
}
  1. 这个时候我们就要想,其中我们数组形参肯定是必不可少,第二个形参我们应该传什么呢? 我们应该传pid 先把第一层拿到,然后再去递归对吧,那么我们思路就清晰了
function getTree (arr,pid){
    let newArr = []
    arr.forEach(item=>{
        if(item.pid === pid) {
            newArr.push(item)
        }
    })
    return  newArr
}
  1. ok 我们这个时候很顺利完成了第一步 , 我们的newArr里面就拿到了一级目录,但是我们此时是不是该想一下我们的参数第二个参数应该传什么呢?

    因为我们的 判断条件是 
        if(item.pid === pid)
    所以我们的第二个形参是不是应该传一个空值 ,不要问为什么 ,我们可以不传,直接等于空,因为我们的递归第二层要用这个形参的位置
    
  2. OK我们一个完成了一半,拿到了一级,我们是不是该,去拿第子级了,是吧? 所以我们开始吧,我们直接在函数的内部调用,此时我们在回顾一下我们的判断条件 if(item.pid === pid) , 这个时候因为我们已经到了函数的内部里面,我们能拿到每一项, 所以我们只需要拿 id 去跟 pid 比较 ,这个时候,我们就可以筛选每个子级

function getTree (arr,pid){
   let newArr = []
   arr.forEach(item=>{
       if(item.pid === pid) {
       
+       let child = getTree (arr,item.id)
       
           newArr.push(item)
       }
   })
   return  newArr
}
  1. 收集起来 , 这个时候我们可以打印看一下,会有多空数组,然后我们需要过滤一下,拿到有数据的数组,然后添加到父级 , 这个就是递归的做法
function getTree (arr,pid){
   let newArr = []
   arr.forEach(item=>{
       if(item.pid === pid) {
          let child = getTree (arr,item.id)
+             if(child.length > 0){
+               item.children = child
+             }
           newArr.push(item)
       }
   })
   return  newArr
}

getTree(list,'')

3. 来一个 层层解析,不用递归的

这就是一步一步的来, 我就不一步一步的带着大家走一遍了

export function tranTreeData(list) {

  const obj = {}
  
// 这里我们拿到 每个对象的键就是 id ,值就是每一项
  list.forEach(item => {
    item.children = []
    obj[item.id] = item
  })

  
  const newArr = []
  
  list.forEach(item => {
    if (obj[item.pid]) {
      obj[item.pid].children.push(item)
    } else {
      newArr.push(item)
    }
  })
  
  return newArr
}


好了,这边已经给大家介绍到这里,以上是我自己的理解,希望可以帮到大家, 欢迎留言我这边一定会第一时间给大家解答,喜欢的可以点赞收藏

🐣---->🦅               还需努力!大家一起进步!!!