JS构建一个树形结构数据

5,265 阅读1分钟
  • 数组:
[
   {
       id: 1,
       name: "1"
       pid: 0,
   },
   {
       id: 2,
       name: "1-1",
       pid: 1
   },
   {
       id: 3,
       name: "1-1-1",
       pid: 2
   },
   {
       id: 4,
       name: "1-2",
       pid: 1
   },
   {
       id: 5,
       name: "1-2-2",
       pid: 4
   },
   {
       id: 6,
       name: "1-1-1-1",
       pid: 3
   },
   {
       id: 7,
       name: "2"
   }
]

项目是用Vue开发,所以把方法添加到Vue的实例方法中

const install = function (Vue, opts) {
   /**
    * [deepClone 数组/对象深度拷贝]
    * @param  {[type]} source [数组/对象]
    * @return {[type]}        [description]
    */
   Vue.prototype.deepClone = function (source) {
       if (!source && typeof source !== 'object') {
           throw new Error('error arguments', 'shallowClone');
       }
       const targetObj = source.constructor === Array ? [] : {};
       for (const keys in source) {
           if (source.hasOwnProperty(keys)) {
               if (source[keys] && typeof source[keys] === 'object') {
                   targetObj[keys] = source[keys].constructor === Array ? [] : {};
                   targetObj[keys] = this.deepClone(source[keys]);
               } else {
                   targetObj[keys] = source[keys];
               }
           }
       }
       return targetObj;
   };
   /**
    * [structureTreeData 构建一个树形结构数据]
    * @param  {[Array]} data [有父子关系的数组]
    * @param  {[String]} id  [节点ID]
    * @param  {[String]} pid [对应父节点ID]
    * @return {[Object]}     [树形结构数据]
    */
   Vue.prototype.structureTreeData = function (data, id = "id", pid = "pid") {
       let pids = [];
       let ids = [];
       data.forEach(item => {
           if (!pids.includes(item.pid)) {
               pids.push(item.pid);
           }
           if (!ids.includes(item.id)) {
               ids.push(item.id);
           }
       });
       //父节点数据
       let parents = data.filter(
           value => !ids.includes(value.pid)
       );
       //子节点数据
       let childrens = data.filter(
           value => ids.includes(value.pid)
       );
       //构造树形结构数据
       let structure = (parents, childrens) => {
           //遍历父节点数据
           parents.forEach(parent => {
               //遍历子节点数据
               childrens.forEach((children, index) => {
                   //此时找到父节点对应的一个子节点
                   if (children.pid === parent.id) {
                       //对子节点数据进行深拷贝
                       let newChildrens = this.deepClone(childrens);
                       //让当前子节点从newChildrens中移除,newChildrens作为新的子节点数据,
                       //这里是为了让递归时,子节点的遍历次数更少,如果父子关系的层级越多,越有利
                       newChildrens.splice(index, 1);
                       //让当前子节点作为唯一的父节点,去递归查找其对应的子节点
                       structure([children], newChildrens);
                       //把找到子节点放入父节点的children属性中
                       typeof parent.children !== "undefined"
                           ? parent.children.push(children)
                           : (parent.children = [children]);
                   }
               });
           });
       };
       //调用构造方法
       structure(parents, childrens);
       return parents;
   };
}
export default {
   install
}