美文网首页
JS 树结构数据各种递归

JS 树结构数据各种递归

作者: Cherry丶小丸子 | 来源:发表于2021-02-04 14:49 被阅读0次
    递归-----树组件节点属性修改
    参数为数组
    
    /**
     * 递归-----树组件节点属性修改
     * @param {Object} data       树的源数据
     * @returns {Object} data     属性修改后的树的数据
     */
    setTreeRecursion(data) {
        data.map((item, index) => {
            item.scopedSlots = { title: 'customNode' };
            if(item.children && item.children.length != 0){
                this.setTreeRecursion(item.children);
            }
        });
        return data;
    }
    setTreeRecursion('树结构数据')
    
    参数为对象
    
    /**
     * 递归-----树组件节点属性修改
     * @param {Object} data       树的源数据
     * @returns {Object} data     属性修改后的树的数据
     */
    setTreeRecursion(data) {
        data.scopedSlots = { title: 'customNode' };
        if(data.children && data.children.length != 0){
            data.children.map((item, index) => {
                this.setTreeRecursion(item);
            });
        }
        return data;
    }
    setTreeRecursion('树结构数据')
    
    递归-----查询 树组件 共有多少节点
    参数为数组
    
    /**
     * 递归-----查询 树组件 共有多少节点
     * @param {Object}      data树的源数据
     * @returns {Number}    num 总节点数
     */
    queryNodesTotal(data, num = 0){
        let forFn = nodes => {
            for(let i = 0; i < nodes.length; i++){
                num++;
                if(nodes[i].children && nodes[i].children.length != 0){
                    forFn(nodes[i].children);
                }
            }
        }
        forFn(data);
        return num;
    }
    queryNodesTotal('树结构数据')
    
    参数为对象
    
    /**
     * 递归-----查询 树组件 共有多少节点
     * @param {Object}      data树的源数据
     * @returns {Number}    num 总节点数
     */
    queryNodesTotal(data, num = 0){
        let forFn = nodes => {
            num++;
            if(nodes.children && nodes.children.length != 0){
                for(let i = 0; i < nodes.children.length; i++){
                    forFn(nodes.children[i]);
                }
            }
        }
        forFn(data);
        return num;
    }
    queryNodesTotal('树结构数据')
    
    
    递归-----取出树组件最后子节点
    /**
     * 递归-----取出树组件最后子节点---对象
     * @param {Object} node      树的源数据
     * @returns {Object} temp    取出树组件最后子节点的集合
     */
    getLastChildNode(node, temp = []) {
        let forFn = (arr) => {
            for (let i = 0; i < arr.length; i++) {
                if (!arr[i].children || arr[i].children.length == 0) {
                    temp.push(arr[i]);
                } else {
                    forFn(arr[i].children);
                    // if(arr[i].children && arr[i].children.length != 0){
                        // forFn(arr[i].children);
                    // }
                }
            }
        }
        forFn(node)
        return temp;
    }
    getLastChildNode('树结构数据')
    
    /**
     * 递归-----取出树组件最后子节点---数组
     * @param {Object} node      树的源数据
     * @returns {Object} temp    取出树组件最后子节点的集合
     */
    getLastChildNode(node, temp = []) {
        let forFn = (arr) => {
            for (let i = 0; i < arr.length; i++) {
                if (!arr[i].children || arr[i].children.length == 0) {
                    temp.push(arr);
                    arr = [];
                } else {
                    forFn(arr[i].children);
                }
            }
        }
        forFn(node)
        return temp;
    }
    getLastChildNode('树结构数据')
    
    递归-----删除树组件源数据的最后子节点
    /**
     * 递归-----删除树组件源数据的最后子节点
     * @param {Object} node      树的源数据
     * @returns {Object} node    删除最后子节点之后的树的数据
     */
    deleteSourceNode(node) {
        for (let i = node.length - 1; i >= 0; i--) {
            if (!node[i].hasOwnProperty('children')) {
                continue;
            }
            if (!node[i].children || node[i].children.length == 0) {
                node.splice(i, 1);
                continue;
            }
            this.deleteSourceNode(node[i].children);
        }
        return node;
    }
    deleteSourceNode('树组件数据')
    
    递归-----根据 id 查询当前节点 或者 根据 pId 查询当前节点的父节点 或者 所有父级点集合
    /**
     * 递归-----根据 id 查询当前节点 或者 根据 pId 查询当前节点的父节点
     * @param node      树的源数据
     * @param nodeId    节点的 id 或者 pId
     * @returns temp    返回的匹配的节点数据
     */
    queryNodeById(node, nodeId, temp = {}){
        let forFn = (arr, id) => {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i].id === id) {
                    temp = arr[i]; // 匹配到的节点 或者 父节点
                    break;
                } else {
                    if (arr[i].children && arr[i].children.length != 0) {
                        forFn(arr[i].children, id);
                    }
                }
            }
        }
        forFn(node, nodeId);
        return temp;
    }
    queryNodeById('树组件数据', '节点的 id 或者 pId')
    
    /**
     * 递归-----根据 根据 pId 查询当前节点的 所有父级点集合
     * @param node      树的源数据
     * @param pId       节点的 pId
     * @returns temp    返回的匹配的节点数据
     */
    queryNodeById(node, pId, temp = []){
        let forFn = (arr, id) => {
            for (let i = 0; i < arr.length; i++) {
                if (arr[i].id === id) {
                    temp.push(arr[i]); // 匹配到的节点 push 到 temp 中
                    forFn(node, arr[i].pId); // 继续递归查询
                    break;
                } else {
                    if (arr[i].children && arr[i].children.length != 0) {
                        forFn(arr[i].children, id);
                    }
                }
            }
        }
        forFn(node, pId);
        return temp;
    }
    queryNodeById('树组件数据', '节点的 pId')
    
    `此方法也可以的第二个参数也可以传入 节点的 id,如果传入的是 id, 则返回的是包含此节点以及所有父级节点
    
    如果传入的仅是此节点的 pId,返回的是不包含此节点的所有父级节点`
    
    /**
     * 递归-----根据 id 查询当前节点 和 根据 pId 查询 当前节点的所有父级节点集合
     * @param node      树的源数据
     * @param nodeId    节点的 id
     * @param nodePid   节点的 pId
     * @param temp      返回的匹配的节点数据集合
     * @returns {{pNodes: *[], cNode: {}}} pNodes: 父级节点集合,cNode:当前节点
     */
    queryNodeById(node, nodeId, nodePid, temp = {cNode: {}, pNodes: []}){
        let forFn = (arr, id, pId) => {
            for (let i = 0; i < arr.length; i++) {
    
                if (arr[i].id === id) {
                    temp.cNode = arr[i];
                    break;
                }else if (arr[i].id === pId) {
                    temp.pNodes.push(arr[i]);
                    forFn(node, id, arr[i].pId);
                    break;
                } else {
                    if (arr[i].children && arr[i].children.length != 0) {
                        forFn(arr[i].children, id, pId);
                    }
                }
    
            }
        }
        forFn(node, nodeId, nodePid);
        return temp;
    }
    
    queryNodeById('树组件数据', '节点的 id', '节点的 pId')
    

    上述 三种方法,都是获取当前节点以及父级节点的方法,如果想要获取当前节点以及子级节点,可以按照上边的方法自行修改

    递归-----树形数据(数组)获取最深层级数
    /**
     * 递归-----树形数据(数组)获取最深层级数
     * @param {Object} treeData   树的源数据
     * @returns {Number} max      最深层级数的值
     */
    getMaxFloor(treeData) {
        let floor = 0;
        let max = 0;
        let deepEach = (data, floor) => {
            data.map((item, index) => {
                item.floor = floor;
                if (floor > max) {
                    max = floor;
                };
                if (item.children && item.children.length != 0) {
                    deepEach(item.children, floor + 1);
                };
            });
        };
        deepEach(treeData, 1);
        return max;
    }
    getMaxFloor('树组件数据')
    
    递归-----将树结构数据格式,转化为 二维数组 表格形式
    node 参数为 数组
    
    /**
     * 递归-----将树结构数据格式,转化为 二维数组 表格形式
     * @param node  树的源数据
     * @param data  树转化为二维数组的数据
     * @param row   临时存储数据
     * @returns {*[]}
     */
    parseTreeToRow(node, data = [], row = []) {
        node.map(item => {
            let obj = {
                id: item.id,
                pId: item.pId,
                label: item.label
            }
            if(item.children && item.children.length != 0){
                this.parseTreeToRow(item.children, data, [...row, obj]);
            }else{
                data.push([...row, obj])
            }
        })
        return data;
    }
    
    this.parseTreeToRow('树的源数据---数组');
    
    node 参数为 对象
    
    /**
     * 递归-----将树结构数据格式,转化为 二维数组 表格形式
     * @param node  树的源数据
     * @param data  树转化为二维数组的数据
     * @param row   临时存储数据
     * @returns {*[]}
     */
    parseTreeToRow(node, data = [], row = []) {
        if (node.children && node.children.length != 0) {
            node.children.map((item, index) => {
                const obj = {
                    id: item.id,
                    pId: item.pId,
                    label: item.label,
                };
                this.parseTreeToRow(item, data, [...row, obj]);
            });
        } else {
            data.push(row);
        }
        return data;
    }
    
    // 需要一个有且只有一个根节点的数据
    let obj = {
        id: '',
        pId: '',
        label: '',
        children: '树组件数据'
    }
    this.parseTreeToRow(obj);
    
    递归----- tree 转 一维数组
    /**
     * 递归----- tree 转 一维数组
     * @param treeData
     * @param arr
     * @returns {*[]}
     */
    treeToArr(treeData = [], arr = []) {
        for (let item of treeData) {
            arr.push(item);
            if (item.children && item.children.length != 0) {
                this.treeToArr(item.children, arr);
            }
        }
        return arr;
    },
    
    递归----- 一维数组 转 tree
    /**
     * 递归----- 一维数组 转 tree (此方法会改变原始数组 data,使用时请注意)
     * @param {Object} data 一维数组
     * @param {Object} pId 最外层父 id (一般为 0)
     */
    arrayToTree(data, pId) {
        let tree = [];
        let temp;
        for (let i = 0; i < data.length; i++) {
            if (data[i].pId == pId) {
                let obj = data[i];
                temp = this.arrayToTree(data, data[i].id);
                if (temp.length > 0) {
                    obj.children = temp;
                }
                tree.push(obj);
            }
        }
        return tree;
    }
    
    let data = [
        { id: '1', pId: '0', label: "一级菜单-1" }, 
        { id: '1-2', pId: '1', label: "二级菜单-1-2" },
        { id: '1-3', pId: '1-2', label: "三级菜单-1-3" },
        { id: '1-4', pId: '1-3', label: "四级菜单-1-4" },
    
        { id: '2', pId: '0', label: "一级菜单-2" },
        { id: '2-1', pId: '2', label: "二级菜单-2-1" },
        { id: '2-1-1', pId: '2-1', label: "三级菜单-2-1-1" },
        { id: '2-1-2', pId: '2-1', label: "三级菜单-2-1-2" }
    ];
    
    // 调用
    arrayToTree(data, '0');
    
    递归-----根据特定数组 匹配 tree 数据,仅保留匹配项
    let brr = ['1', '2', '3']
    let arr = [
        {
            id: '1',
            pid: '0',
            name: '1',
            children: [
                {
                    id: '1-1',
                    pid: '0',
                    name: '1-1',
                    children: []
                }
            ]
        },
        {
            id: '2',
            pid: '0',
            name: '2',
            children: []
        },
        {
            id: '3',
            pid: '0',
            name: '3',
            children: []
        }
    ];
    
    /**
     * 递归-----根据特定数组 匹配 tree 数据,仅保留匹配项
     * @param localRoute 第一个比较的数组
     * @param returnRoute 第二个比较的数组
     * @returns {*}
     */
    matchSpecialData(localRoute, returnRoute) {
        for (let i = 0; i < localRoute.length; i++) {
            if(localRoute[i].children && localRoute[i].children.length != 0){
                this.matchSpecialData(localRoute[i].children, returnRoute);
            }
            let flag = false;
            for(let j = 0; j < returnRoute.length; j++){
                if(localRoute[i].name == returnRoute[j]){
                    flag = true;
                    break;
                }
            }
            if(!flag){
                localRoute.splice(i--, 1);
            }
        }
        return localRoute;
    }
    
    this.matchSpecialData(arr, brr);
    

    相关文章

      网友评论

          本文标题:JS 树结构数据各种递归

          本文链接:https://www.haomeiwen.com/subject/dvjbtltx.html