概述

树形数据结构化即把扁平化的数据转化为树形结构,此操作在前端应用的场景有,处理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)
最后修改:2022 年 10 月 25 日
如果觉得我的文章对你有用,请随意赞赏