秃头笔记1——树状对象

在平时的开发中,咱们常常会遇到树状对象的问题,例如:多级菜单、多级部门、多级文件夹等。通常状况下,咱们在数据库中会把这些信息存成平面结构,每一条数据之间有关联字段,例如parentId和id。前端

一般的前端树组件中会要求咱们传入一个树状对象,可是在数据库中存储的都是平面结构的对象(简称平面对象),这就须要咱们将现有的数据结构进行组装。服务器的资源是宝贵的,因此咱们应该尽量的将这一部分工做交至前端来完成。因而我写了这么一段代码,但愿对你们有所帮助,若是有什么不正确的地方,欢迎指正。数据库

/**
     * @conf childrenTag        子集合字段名,默认children
     * @conf keyMap.id          节点惟一标识字段名,默认id
     * @conf keyMap.parentId    父节点惟一标识字段名,默认parentId
     *
     * @method toSingle         树状对象转平面对象
     * @method toList           平面对象转树状对象
     */
    window.treeUtil = {
        childrenTag: 'children',
        keyMap: {id: 'id', parentId: 'parentId'},
        toSingle: function (obj) {
            if (obj instanceof Array) {
                var result = [];
                for (var i in obj) {
                    result.push(obj[i]);
                    if (obj[i][this.childrenTag]) {
                        result = result.concat(this.toSingle(obj[i][this.childrenTag]));
                        delete obj[i][this.childrenTag];
                    }
                }
                return result;
            } else if (obj instanceof Object) {
                return obj;
            } else {
                throw Error('It not is a Array or Object.');
            }
        },
        toList: function (arr) {
            // 查询根节点
            var temp = this.findRootList(arr);
            return this.findChildList(temp.rootNds, temp.otherNds);
        },
        findChildList: function (rootNds, childNds) {
            for (var i in rootNds) {
                var recordIndex = [];
                rootNds[i][this.childrenTag] = [];
                for (var j in childNds) {
                    if (childNds[j][this.keyMap.parentId] === rootNds[i][this.keyMap.id]) {
                        rootNds[i][this.childrenTag].push(childNds[j]);
                        recordIndex.push(j);
                    }
                }
                // 尽量的删去已经使用过的对象,用来减小递归时的循环次数。
                // 这里为了避免让数组长度影响循环,从大到小遍历
                for (var k = recordIndex.length - 1; k >= 0; k--) {
                    childNds.splice(recordIndex[k], 1);
                }
                if (childNds.length > 0) {
                    this.findChildList(rootNds[i][this.childrenTag], childNds);
                }
            }
            return rootNds;
        },
        findRootList: function (arr) {
            var rootNds = [], otherNds = [];
            for (var i = 0; i < arr.length; i++) {
                var flag = true;
                for (var j = 0; i !== j && j < arr.length; j++) {
                    if (arr[i][this.keyMap.parentId] === arr[j][this.keyMap.id]) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    rootNds.push(arr[i]);
                } else {
                    otherNds.push(arr[i]);
                }
            }
            return {rootNds: rootNds, otherNds: otherNds};
        }
    };
复制代码

这里提供了两个可用的方法,toSingle和toList。toSingle是将树状对象转换为平面对象,toList反之。为了可扩展性,不要去将关联字段硬编码化,采用配置的方法:childrenTag字段和keyMap对象用来管理数据之间的关联关系。数组

接下来咱们来验证一下效果:bash

var list1 = [
        {
            "id": 1,
            "name": "新建文件夹1",
            "type": 1,
            "parentId": 0,
            "children": [{"id": 3, "name": "新建文件夹3", "type": 1, "parentId": 1, "children": []}, {
                "id": 4,
                "name": "新建文件夹4",
                "type": 2,
                "parentId": 1,
                "children": [{"id": 8, "name": "新建文件夹8", "type": 2, "parentId": 4, "children": []}, {
                    "id": 9,
                    "name": "新建文件夹9",
                    "type": 2,
                    "parentId": 4,
                    "children": []
                }]
            }]
        }, {
            "id": 2,
            "name": "新建文件夹2",
            "type": 1,
            "parentId": 0,
            "children": [{
                "id": 5,
                "name": "新建文件夹5",
                "type": 2,
                "parentId": 2,
                "children": [{"id": 10, "name": "新建文件夹10", "type": 2, "parentId": 5}]
            }, {"id": 6, "name": "新建文件夹6", "type": 2, "parentId": 2, "children": []}, {
                "id": 7,
                "name": "新建文件夹7",
                "type": 2,
                "parentId": 2,
                "children": []
            }]
        }
    ];
    console.log(treeUtil.toSingle(list1));
复制代码

result: 服务器

abc.png

接下来再验证一下toList:数据结构

var list2 = [
        {"id": 1, "name": "新建文件夹1", "type": 1, "parentId": 0},
        {"id": 3, "name": "新建文件夹3", "type": 1, "parentId": 1},
        {"id": 4, "name": "新建文件夹4", "type": 2, "parentId": 1},
        {"id": 8, "name": "新建文件夹8", "type": 2, "parentId": 4},
        {"id": 9, "name": "新建文件夹9", "type": 2, "parentId": 4},
        {"id": 2, "name": "新建文件夹2", "type": 1, "parentId": 0},
        {"id": 5, "name": "新建文件夹5", "type": 2, "parentId": 2},
        {"id": 10, "name": "新建文件夹10", "type": 2, "parentId": 5},
        {"id": 6, "name": "新建文件夹6", "type": 2, "parentId": 2},
        {"id": 7, "name": "新建文件夹7", "type": 2, "parentId": 2}
    ];
    console.log(treeUtil.toList(list2));
复制代码

result: ui

def.png

本次分享就到这里。若有问题,请联系做者。 若是这篇文章对你有帮助,请点击喜欢来收藏此文章。this

相关文章
相关标签/搜索