当前位置:网站首页>js通过递归实现树形数据操作

js通过递归实现树形数据操作

2022-06-10 10:54:00 SwJieJie

一、处理复杂数据结构转成树形数据操作

案列一如下:
需求分析
1,根据fatherTreeCode判断是不是父级,为空是父级,然后处理成树形层级关系。
2,完成树形结构后再树形数据里面添加对应的key和value值进行显示。
原数据

  const treeData = [
    {
    
      capList: [],
      fatherTreeCode: "",
      isLeaf: "0",
      showSeqno: "1",
      treeCode: "TRE0rv",
      treeLevel: "1",
      treeName: "根目录",
    },
    {
    
      capList: [],
      fatherTreeCode: "TRE0rv",
      isLeaf: "0",
      showSeqno: "4",
      treeCode: "TRE0sw",
      treeLevel: "2",
      treeName: "物联网",
    },
    {
    
      fatherTreeCode: "TRE0rv",
      isLeaf: "1",
      showSeqno: "4",
      treeCode: "TRE0xw",
      treeLevel: "2",
      treeName: "云网业务",
      capList: [
        {
    
          code: "del-vpn",
          id: "8c15d2488ad24d55946e6ce0f5ea3f40",
          name: "5G切片开通",
          treeLevel: "12",

        },
        {
    
          code: "netpe-resource-allocation-request",
          id: "35202810e96442fda4d6aaa61122986b",
          name: "5G资源预占",
          treeLevel: "13",

        },
      ],
    },
  ];

代码如下:

 function tree (data) {
    
    const obj = {
    }
    for (const item of data) {
    
      obj[item.treeCode] = item
    }
    const result = []
    for (const item of data) {
    
      if (obj[item.fatherTreeCode]) {
    
        if (!obj[item.fatherTreeCode].capList) {
    
          obj[item.fatherTreeCode].capList = []
        }
        obj[item.fatherTreeCode].capList.push(item)
      } else {
    
        result.push(item)
      }
    }
    return result
  }
  let list = tree(treeData);
  console.log(list, 'list');
  function fn (data, index = '0-') {
    
    return data.map((item, indexItem) => {
    
      return {
    
        value: `${
      index}${
      indexItem}`,
        key: item.treeLevel,
        treeName: item.treeName || item.name,
        children: (() => {
    
          if (item.capList && item.capList.length > 0) {
    
            return fn(item.capList, `${
      index}${
      indexItem}-`);
          } else {
    
            return []
          }
        })()
      }
    })
  }
  console.log(fn(list));

处理后的数据
在这里插入图片描述
案列二如下:
需求分析:
据id和parentId把json数据结构转成树形状的数据结构
原数据

  const temp = [
      {
    
        'id': 1,
        'name': '1级1',
        'parentId': 0
      },
      {
    
        'id': 2,
        'name': '2级1',
        'parentId': 0
      },
      {
    
        'id': 4,
        'name': '1级1-1',
        'parentId': 1
      },
      {
    
        'id': 6,
        'name': '1级1-1-1',
        'parentId': 4
      },
      {
    
        'id': 12,
        'name': '2级1-1',
        'parentId': 2
      },
      {
    
        'id': 13,
        'name': '3级1',
        'parentId': 0
      },
      {
    
        'id': 14,
        'name': '3级1-1',
        'parentId': 13
      },
      {
    
        'id': 15,
        'name': '1级1-1-1-1',
        'parentId': 6
      }
  ]

代码如下:
方法一:

const transData = (jsonArr, idStr, pidStr, childrenStr) => {
    
      // 存放的最终结果树数组
      const result = [];
      const id = idStr;
      const parentId = pidStr;
      const children = childrenStr;
      const len = jsonArr.length;

      // 遍历得到以id为键名的对象(建立整棵树的索引)
      const hash = {
    };
      jsonArr.forEach(item => {
    
           hash[item[id]] = item;
      });

      for (let j = 0; j < len; j++) {
    
          const jsonArrItem = jsonArr[j];
          const hashItem = hash[jsonArrItem[parentId]];
          if (hashItem) {
    
              // 如果当前项还没有children属性,则添加该属性并设置为空数组
              !hashItem[children] && (hashItem[children] = []);
              hashItem[children].push(jsonArrItem);
          } else {
    
              result.push(jsonArrItem);
          }
      }
      return result;
  };

  const jsonDataTree = transData(temp, 'id', 'parentId', 'children');
  console.log(jsonDataTree)

方法二:

	// 调用方法, temp为原始数据, result为树形结构数据
	var result = generateOptions(temp)

	// 开始递归方法
	generateOptions(params) {
    
      var result = []
      for (const param of params) {
    
        if (param.parentId === 0) {
      // 判断是否为顶层节点
          var parent = {
    
            'id': param.id,
            'label': param.name
          }
          parent.children = this.getchilds(param.id, params)  // 获取子节点
          result.push(parent)
        }
      }
      return result
    },

    getchilds(id, array) {
    
      const childs = []
      for (const arr of array) {
      // 循环获取子节点
        if (arr.parentId === id) {
    
          childs.push({
    
            'id': arr.id,
            'label': arr.name
          })
        }
      }
      for (const child of childs) {
     // 获取子节点的子节点
        const childscopy = this.getchilds(child.id, array)// 递归获取子节点
        if (childscopy.length > 0) {
    
          child.children = childscopy
        }
      }
      return childs
    }

递归生成后的树形结构数据
在这里插入图片描述

二、重新组合树结构中的数据

对原有的树形结构添加新的字段值
原数据

const treeData = [{
    
    name: '2021资源',
    key: '1',
    isLeaf: false,
    children: [{
    
        name: '服务器',
        isLeaf: false,
        key: '6',
        children: [
            {
    
                isLeaf: false,
                name: '172.168.201.109',
                key: '5',
                children: [
                    {
    
                        isLeaf: true,
                        children: [],
                        name: 'ping丢包率',
                        key: '2',
                    }, {
    
                        isLeaf: true,
                        children: [],
                        name: 'ping状态',
                        key: '3',
                    },
                ],
            },
            {
    
                isLeaf: true,
                children: [],
                name: '192.168.3.6',
                key: '7',
            },
        ],
    }],
}];
// 重新组合树数据(根据需要来重组树结构中的属性字段)
const dealTreeData = (treeData) => {
    
    const data = treeData.map((item) => ({
    
        ...item,
        // 新增title字段
        title: item.name,
        // 如果children为空数组,则置为null
        children: (item.children && item.children.length)
            ? dealTreeData(item.children)
            : null,
    }));
    return data;
};

console.log(JSON.stringify(dealTreeData(treeData)));

结果:

// 打印结果
// [{
    
// name: '2021资源',
// key: '1',
// isLeaf: false,
// title: '2021资源',
// children: [{
    
// name: '服务器',
// isLeaf: false,
// key: '6',
// title: '服务器',
// children: [{
    
// isLeaf: false,
// name: '172.168.201.109',
// key: '5',
// title: '172.168.201.109',
// children: [{
    
// isLeaf: true,
// children: null,
// name: 'ping丢包率',
// key: '2',
// title: 'ping丢包率',
// }, {
    
// isLeaf: true,
// children: null,
// name: 'ping状态',
// key: '3',
// title: 'ping状态',
// }],
// }, {
    
// isLeaf: true,
// children: null,
// name: '192.168.3.6',
// key: '7',
// title: '192.168.3.6',
// }],
// }],
// }];

三、树形结构的基本操作使用

(1),获取树中的所有祖先节点名称

const treeData = [{
    
    key: '全部',
    title: '全部',
    isLeaf: false,
    children: [{
    
        key: '数据库',
        title: '数据库',
        isLeaf: false,
        children: [
            {
    
                key: 'mysql',
                title: 'mysql',
                isLeaf: false,
                children: [
                    {
    
                        key: '137',
                        title: 'QPS',
                        isLeaf: true,
                    }, {
    
                        key: '146',
                        title: 'MySQL进程信息',
                        isLeaf: true,
                    },
                ],
            },
            {
    
                key: 'oracle',
                title: 'oracle',
                isLeaf: false,
                children: [
                    {
    
                        key: '137',
                        title: 'QPS',
                        isLeaf: true,
                    },
                ],
            },
        ],
    }],
}];

// 获取树的所有祖先节点名称
const getTreeParents = (data) => {
    
    const parentKey = [];
    data.forEach((item) => {
    
        if (item.children && item.children.length) {
    
            parentKey.push(item.key);
            const temp = getTreeParents(item.children);
            if (temp.length) {
    
                parentKey.push(...temp);
            }
        }
    });
    return parentKey;
};

const parentKeys = getTreeParents(treeData);
console.log(parentKeys); // ["全部", "数据库", "mysql", "oracle"]

(2),获取树中叶子节点的总个数(节点中isLeaf为true的节点)

const treeData = {
    
    name: '2021资源',
    title: '2021资源',
    key: '1',
    isLeaf: false,
    children: [{
    
        name: '服务器',
        isLeaf: false,
        title: '服务器',
        key: '6',
        children: [
            {
    
                name: '172.168.201.109',
                isLeaf: false,
                title: '172.168.201.109',
                key: '5',
                children: [
                    {
    
                        name: 'ping丢包率',
                        isLeaf: true,
                        children: null,
                        title: 'ping丢包率',
                        key: '2',
                    }, {
    
                        name: 'ping状态',
                        isLeaf: true,
                        children: null,
                        title: 'ping状态',
                        key: '3',
                    },
                ],
            },
            {
    
                name: '192.168.3.6',
                isLeaf: true,
                children: null,
                title: '192.168.3.6',
                key: '7',
            },
        ],
    }],
};

const getLeafNum = (treeNode) => {
    
    let leafNum = 0;
    if (!treeNode) {
    
        return leafNum;
    }
    if (treeNode.children && treeNode.children.length) {
    
        treeNode.children.forEach((item) => {
    
            leafNum += getLeafNum(item);
        });
    } else {
    
        if (treeNode.isLeaf) {
    
            leafNum++;
        }
    }
    return leafNum;
};
console.log(getLeafNum(treeData)); // 3

(3),根据过滤条件筛选出需要留下节点的树结构数据(般用于前端做树的查询功能。)

/** * 递归过滤节点,但保留原树结构,即符合条件节点的父路径上所有节点不管是否符合条件都保留 * @param {Node[]} nodes 要过滤的树 * @param {node => boolean} predicate 过滤条件,符合条件的节点保留(参数为函数,返回值为布尔值) * @param {node => boolean} wrapMatchFn 层级条件(参数为函数,返回值为布尔值) * @return 过滤后的包含根节点数组 */
export const filterSearchTree = (nodes, predicate, wrapMatchFn = () => false) => {
    
  // 如果已经没有节点了,结束递归
  if (!(nodes && nodes.length)) {
    
    return []
  }
  const newChildren = []
  for (let i = 0; i < nodes.length; i++) {
    
    const node = nodes[i]
    // 想要截止匹配的那一层(如果有匹配的则不用递归了,直接取下面所有的子节点)
    if (wrapMatchFn(node) && predicate(node)) {
    
      newChildren.push(node)
      continue
    }
    const subs = filterSearchTree(node.children, predicate, wrapMatchFn)

    // 以下两个条件任何一个成立,当前节点都应该加入到新子节点集中
    // 1. 子孙节点中存在符合条件的,即 subs 数组中有值
    // 2. 自己本身符合条件
    if ((subs && subs.length) || predicate(node)) {
    
      node.children = subs || []
      newChildren.push(node)
    }
  }
  return newChildren.length ? newChildren : []
}

const treeData = [{
    
    key: '全部',
    title: '全部',
    isLeaf: false,
    children: [{
    
        key: '数据库',
        title: '数据库',
        isLeaf: false,
        children: [
            {
    
                key: 'mysql',
                title: 'mysql',
                isLeaf: false,
                children: [
                    {
    
                        key: '142',
                        title: '慢查询',
                        isLeaf: true,
                    }, {
    
                        key: '137',
                        title: 'QPS',
                        isLeaf: true,
                    }, {
    
                        key: '143',
                        title: '用户列表',
                        isLeaf: true,
                    },
                ],
            },
            {
    
                key: '166',
                title: 'SQL',
                isLeaf: true,
            },
        ],
    }],
}];

// 要查找的关键字
const searchValue = 'S';

// 筛选到的树结构数据
const newTreeData = filterSearchTree(
    treeData,
    (node) => {
    
        if (node.title.indexOf(searchValue) !== -1) {
    
            return true;
        }
        return false;
    },
);
// const newTreeData = filterSearchTree(
// cloneTreeDatas,
// (node) => {
    
// if (node.title.includes(searchValue)) {
    
// return true
// }
// return false
// },
// (node) => {
    
// // 第二层(显示左侧角色组数据)
// if (node.groupName) {
    
// return true
// }
// return false
// }
// )
console.log(JSON.stringify(newTreeData));
// 打印的结果
// [{
    
// key: '全部',
// title: '全部',
// isLeaf: false,
// children: [{
    
// key: '数据库',
// title: '数据库',
// isLeaf: false,
// children: [{
    
// key: 'mysql',
// title: 'mysql',
// isLeaf: false,
// children: [{
    
// key: '137',
// title: 'QPS',
// isLeaf: true,
// children: null,
// }],
// }, {
    
// key: '166',
// title: 'SQL',
// isLeaf: true,
// children: null,
// }],
// }],
// }];
原网站

版权声明
本文为[SwJieJie]所创,转载请带上原文链接,感谢
https://blog.csdn.net/qq_44552416/article/details/124949807