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-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为空数组,则置为nullchildren: (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,
// }],
// }],
// }];
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!