基础配置
// 默认配置
const DEFAULT_CONFIG = {
id: 'id',
children: 'children',
pid: 'pid',
};
函数集合
-
数组转树列表
export function listToTree<T = any>(list: any[], config = DEFAULT_CONFIG): T[] { const nodeMap = new Map(); const result: T[] = []; const { id, children, pid } = config; for (const node of list) { node[children] = node[children] || []; nodeMap.set(node[id], node); } for (const node of list) { const parent = nodeMap.get(node[pid]); (parent ? parent[children] : result).push(node); } return result; }let d =[{"id":1,"pid":0,"name":"1"},{"id":2,"pid":0,"name":"2"},{"id":3,"pid":0,"name":"3"},{"id":4,"pid":1,"name":"4"},{"id":5,"pid":4,"name":"5"},{"id":6,"pid":2,"name":"6"},{"id":7,"pid":3,"name":"7"},{"id":8,"pid":4,"name":"8"},{"id":9,"pid":8,"name":"9"}]
转换结果为
[{"id":1,"pid":0,"name":"1","children":[{"id":4,"pid":1,"name":"4","children":[{"id":5,"pid":4,"name":"5","children":[]},{"id":8,"pid":4,"name":"8","children":[{"id":9,"pid":8,"name":"9","children":[]}]}]}]},{"id":2,"pid":0,"name":"2","children":[{"id":6,"pid":2,"name":"6","children":[]}]},{"id":3,"pid":0,"name":"3","children":[{"id":7,"pid":3,"name":"7","children":[]}]}]
-
树列表转数组
export function treeToList<T = any>(tree: any, config= DEFAULT_CONFIG): T { const { children } = config; const result: any = [...tree]; for (let i = 0; i < result.length; i++) { if (!result[i][children!]) continue; result.splice(i + 1, 0, ...result[i][children!]); } return result; } -
查找一个元素
export function findNode<T = any>( tree: any, func: Fn, config=DEFAULT_CONFIG, ): T | null { const { children } = config; const list = [...tree]; for (const node of list) { if (func(node)) return node; node[children!] && list.push(...node[children!]); } return null; }console.log(JSON.stringify(findNode(d, (o) => o.id > 6))){"id":7,"pid":3,"name":"7","children":[]}
-
查找所有符合条件的元素
export function findNodeAll<T = any>( tree: any, func: Fn, config=DEFAULT_CONFIG, ): T[] { const { children } = config; const list = [...tree]; const result: T[] = []; for (const node of list) { func(node) && result.push(node); node[children!] && list.push(...node[children!]); } return result; } -
查找符合条件的元素路径(祖先节点=>父节点=>查找节点)
export function findPath<T = any>( tree: any, func: Fn, config=DEFAULT_CONFIG, ): T | T[] | null { const path: T[] = []; const list = [...tree]; const visitedSet = new Set(); const { children } = config; while (list.length) { const node = list[0]; if (visitedSet.has(node)) { path.pop(); list.shift(); } else { visitedSet.add(node); node[children!] && list.unshift(...node[children!]); path.push(node); if (func(node)) { return path; } } } return null; }console.log(JSON.stringify(findPath(d, (o) => o.id == 5)))// 第一层 [{"id":1,"pid":0,"name":"1","children":[{"id":4,"pid":1,"name":"4","children":[{"id":5,"pid":4,"name":"5","children":[]},{"id":8,"pid":4,"name":"8","children":[{"id":9,"pid":8,"name":"9","children":[]}]}]}]}, // 第二层 {"id":4,"pid":1,"name":"4","children":[{"id":5,"pid":4,"name":"5","children":[]},{"id":8,"pid":4,"name":"8","children":[{"id":9,"pid":8,"name":"9","children":[]}]}]}, // 查找节点 {"id":5,"pid":4,"name":"5","children":[]}]应用:如某用户属于行政部->人事科->材料管理员 ,可用该方法
-
查找所有符合条件的元素路径
export function findPathAll(tree: any, func: Fn,config=DEFAULT_CONFIG) { const path: any[] = []; const list = [...tree]; const result: any[] = []; const visitedSet = new Set(), { children } = config; while (list.length) { const node = list[0]; if (visitedSet.has(node)) { path.pop(); list.shift(); } else { visitedSet.add(node); node[children!] && list.unshift(...node[children!]); path.push(node); func(node) && result.push([...path]); } } return result; }console.log(JSON.stringify(findPath(d, (o) => o.id > 5)))数据结构[第一个,第二个,第三个],每一个数据同
findPath()
-
查找符合条件的元素(如果有父元素,则最后一级为查找元素)
export function filterNode<T = any>( tree: T[], func: (n: T) => boolean, config=DEFAULT_CONFIG ): T[] { const children = config.children as string; function listFilter(list: T[]) { return list .map((node: any) => ({ ...node })) .filter((node) => { // 递归调用 对含有children项 进行再次调用自身函数 listFilter node[children] = node[children] && listFilter(node[children]); // 执行传入的回调 func 进行过滤 return func(node) || (node[children] && node[children].length); }); } return listFilter(tree); }console.log(JSON.stringify(filter(d, (o) => o.id == 4)))[ { "id": 1, "pid": 0, "name": "1", "children": [ { "id": 4, "pid": 1, "name": "4", "children": [] } ] } ]
-
递归处理树数据
export function eachTree(treeDatas: any[], callBack: Fn, parentNode = {}) { treeDatas.forEach((element) => { const newNode = callBack(element, parentNode) || element; if (element.children) { eachTree(element.children, callBack, newNode); } }); }eachTree(d, o) => { o.name = o.name + 'nihao' return o }) console.log(JSON.stringify(d)) //[{"id":1,"pid":0,"name":"1nihao","children":[{"id":4,"pid":1,"name":"4nihao","children":[{"id":5,"pid":4,"name":"5nihao","children":[]},{"id":8,"pid":4,"name":"8nihao","children":[{"id":9,"pid":8,"name":"9nihao","children":[]}]}]}]},{"id":2,"pid":0,"name":"2nihao","children":[{"id":6,"pid":2,"name":"6nihao","children":[]}]},{"id":3,"pid":0,"name":"3nihao","children":[{"id":7,"pid":3,"name":"7nihao","children":[]}]}]
-
循环处理树数据
export function forEach<T = any>( tree: T[], func: (n: T) => any, config=DEFAULT_CONFIG ): void { const list: any[] = [...tree]; const { children } = config; for (let i = 0; i < list.length; i++) { //func 返回true就终止遍历,避免大量节点场景下无意义循环,引起浏览器卡顿 if (func(list[i])) { return; } children && list[i][children] && list.splice(i + 1, 0, ...list[i][children]); } }forEach2(d, (o) => {
o.name = o.name + 'nihao'
// return true 就终止遍历
return false
})
完整代码 如果觉得文章对你有帮助,欢迎一键三连