js实现无限层级树形数据结构

JavaScript4年前 (2020)更新 小马大哥哥
735 0 0

js代码:把扁平数据转成树形数据

function treeData(source, id, parentId, children){   
    let cloneData = JSON.parse(JSON.stringify(source))
    return cloneData.filter(father=>{
        let branchArr = cloneData.filter(child => father[id] == child[parentId]);
        branchArr.length>0 ? father[children] = branchArr : ''
        return father[parentId] == 0        // 如果第一层不是parentId=0,请自行修改
    })
}
 
// 调用时,字段名以字符串的形式传参,如treeData(source, 'id', 'parentId', 'children')

vue组件中使用:

<template>
  <el-tree
    :data="treeData"
    :props="defaultProps"
    accordion
    @node-click="handleNodeClick">
  </el-tree>
</template>
 
<script>
    export default {
        name: "Test",
      data(){
        return {
          data : [
            {id:1,parentId:0,name:"一级菜单A",rank:1},
            {id:2,parentId:0,name:"一级菜单B",rank:1},
            {id:3,parentId:0,name:"一级菜单C",rank:1},
            {id:4,parentId:1,name:"二级菜单A-A",rank:2},
            {id:5,parentId:1,name:"二级菜单A-B",rank:2},
            {id:6,parentId:2,name:"二级菜单B-A",rank:2},
            {id:7,parentId:4,name:"三级菜单A-A-A",rank:3},
            {id:8,parentId:7,name:"四级菜单A-A-A-A",rank:4},
            {id:9,parentId:8,name:"五级菜单A-A-A-A-A",rank:5},
            {id:10,parentId:9,name:"六级菜单A-A-A-A-A-A",rank:6},
            {id:11,parentId:10,name:"七级菜单A-A-A-A-A-A-A",rank:7},
            {id:12,parentId:11,name:"八级菜单A-A-A-A-A-A-A-A",rank:8},
            {id:13,parentId:12,name:"九级菜单A-A-A-A-A-A-A-A-A",rank:9},
            {id:14,parentId:13,name:"十级菜单A-A-A-A-A-A-A-A-A-A",rank:10},
          ],
          defaultProps: {
            children: 'children',
            label: 'name'
          }
        }
      },
      computed:{
        treeData(){
          let cloneData = JSON.parse(JSON.stringify(this.data))    // 对源数据深度克隆
          return cloneData.filter(father=>{               
            let branchArr = cloneData.filter(child=>father.id == child.parentId)    //返回每一项的子级数组
            branchArr.length>0 ? father.children = branchArr : ''   //如果存在子级,则给父级添加一个children属性,并赋值
            return father.parentId==0;      //返回第一层
          });
        }
      },
      methods:{
        handleNodeClick(data){
          // console.log(data)
          console.log(this.treeData)
        }
      },
      mounted(){
      }
    }
</script>
 
<style scoped>
 
</style>

js实现树级递归,通过js生成tree树形菜单(递归算法)

方法封装:

/**
 * 数据转换为树形(递归),示例:toTreeByRecursion(source, 'id', 'parentId', null, 'children')
 * @param {Array} source 数据
 * @param {String} idField 标识字段名称
 * @param {String} parentIdField 父标识字段名称
 * @param {Any} parentIdNoneValue 父级标识空值
 * @param {String} childrenField 子节点字段名称
 * @param {Object} treeOption tree树形配置
 */function toTreeByRecursion (
  source = [],
  idField = 'id',
  parentIdField = 'parentId',
  parentIdNoneValue = '',
  childrenField = 'children',
  treeOption = undefined
) {
  const treeOptions = {
    enable: false, // 是否开启转tree插件数据
    keyField: 'key', // 标识字段名称,默认为key
    valueField: 'value', // 值字段名称,默认为value
    titleField: 'title', // 标题字段名称,默认为title

    keyFieldBind: 'id', // 标识字段绑定字段名称,默认为id
    valueFieldBind: 'id', // 值字段名称绑定字段名称,默认为id
    titleFieldBind: 'name' // 标题字段名称绑定字段名称,默认为name
  }
  // 合并tree树形配置
  if (treeOption) {
    Object.assign(treeOptions, treeOption)
  }

  // 对源数据深度克隆
  const cloneData = JSON.parse(JSON.stringify(source))
  return cloneData.filter(parent => {
    // 返回每一项的子级数组
    const branchArr = cloneData.filter(child => parent[idField] === child[parentIdField])

    // 绑定tree树形配置
    if (treeOptions.enable) {
      branchArr.map(child => {
        child[treeOptions.keyField] = child[treeOptions.keyFieldBind]
        child[treeOptions.valueField] = child[treeOptions.valueFieldBind]
        child[treeOptions.titleField] = child[treeOptions.titleFieldBind]
        return child
      })
    }

    // 如果存在子级,则给父级添加一个children属性,并赋值,否则赋值为空数组
    if (branchArr.length > 0) {
      parent[childrenField] = branchArr
    } else {
      parent[childrenField] = []
    }

    // 绑定tree树形配置
    if (treeOptions.enable) {
      parent[treeOptions.keyField] = parent[treeOptions.keyFieldBind]
      parent[treeOptions.valueField] = parent[treeOptions.valueFieldBind]
      parent[treeOptions.titleField] = parent[treeOptions.titleFieldBind]
    }

    return parent[parentIdField] === parentIdNoneValue // 返回第一层
  })
}

使用示例:

var jsonData = [
  {
    id: '1',
    name: '1',
    parentId: null,
    rank: 1
  },
  {
    id: '2',
    name: '1-1',
    parentId: '1',
    rank: 1
  },
  {
    id: '3',
    name: '1-2',
    parentId: '1',
    rank: 1
  },

  {
    id: '4',
    name: '2',
    parentId: null,
    rank: 1
  },
  {
    id: '5',
    name: '2-1',
    parentId: '4',
    rank: 1
  },
  {
    id: '6',
    name: '2-2',
    parentId: '4',
    rank: 1
  },
  {
    id: '7',
    name: '2-2-1',
    parentId: '6',
    rank: 1
  }
]
const treeOption = {
  enable: false, // 是否开启转tree插件数据
  keyField: 'key', // 标识字段名称
  valueField: 'value', // 值字段名称
  titleField: 'title', // 标题字段名称

  keyFieldBind: 'id', // 标识字段绑定字段名称
  valueFieldBind: 'id', // 值字段名称绑定字段名称
  titleFieldBind: 'name' // 标题字段名称绑定字段名称
}
const treeData = toTreeByRecursion(jsonData, 'id', 'parentId', null, 'children', treeOption)
console.log(treeData)
js实现无限层级树形数据结构

说明:

  • parentIdNoneValue 父级标识空值这个参数如果跟你数据无父级时的值不一致时,就配置这个参数。比如:这里默认值为null,你根节点parentId的值为-1或”。
  • treeOption 参数可以不传,如果要绑定tree树形控件(一般都会有key、value、title这三个字段),那就需要配置这个参数,如果参数默认的配置跟你的不一样,那就通过参数覆盖的方式重新定义。
  • treeOption 的三个绑定字段是指绑定你数据中的字段,实质就是把原数据字段绑定的tree树形控件需要的三个字段key、value、title。
© 版权声明

相关文章

暂无评论

您必须登录才能参与评论!
立即登录
暂无评论...