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

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

案列一如下:
需求分析
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-",
          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));

处理后的数据
js通过递归实现树形数据操作_第1张图片
案列二如下:
需求分析:
据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
    }

递归生成后的树形结构数据
js通过递归实现树形数据操作_第2张图片

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

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

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,
//         }],
//     }],
// }];

你可能感兴趣的:(Js,javascript,开发语言,ecmascript)