typescript-util
Version:
JS/TS 的简单工具
128 lines • 4.28 kB
JavaScript
import { ArrayTool } from './ArrayTool';
/**
* TreeTool
* @author 冰凝
* @date 2022-09-19 09:45:27
**/
export class TreeTool {
/**
* 根据指定子节点, 递归寻找所在树中 从根节点到指定节点路径上所有节点
* @template {Constructor<{}>} NODE
* @param data {NODE | NODE[]}树
* @param currentNode {NODE} 目标节点
* @param id {string} 判断是否相等的属性名, 默认 id
* @param child {string} 子节点属性名, 默认 children
* @return {NODE[]}
*/
static treePath(data, currentNode, id = 'id', child = 'children') {
const pathArr = [];
let find = false;
const recursionTree = (treeData) => {
if (find) {
return;
}
// 数组
if (Array.isArray(treeData)) {
for (const treeDataItem of treeData) {
recursionTree(treeDataItem);
if (find) {
return;
}
}
return;
}
// 对象
// @ts-ignore
if (treeData[id] === currentNode[id]) {
find = true;
pathArr.push(treeData);
return;
}
// 树节点
// @ts-ignore
const childList = treeData[child];
if (Array.isArray(childList) && childList.length > 0) {
for (const c of childList) {
// 深度 +1
pathArr.push(treeData);
recursionTree(c);
if (find) {
return;
}
else {
pathArr.pop();
}
}
}
};
recursionTree(data);
return pathArr;
}
/**
* 树结构遍历
* @param treeArr 源树结构数组
* @param map 需要对节点元素执行操作的映射器
* @param {[] | null} emptyChildren 空子节点使用什么值代替, 默认 []
* @param children Children 属性名, 默认 children
* @returns 映射器返回的结果的数组
*/
static treeEach(treeArr, map, emptyChildren = [], children) {
if (ArrayTool.isEmpty(treeArr)) {
return emptyChildren;
}
return treeArr.map(i => {
const propertyName = children || 'children';
// @ts-ignore
if (this.isNotEmpty(i[propertyName])) {
// @ts-ignore
i[propertyName] = this.treeEach(i[propertyName], map, emptyChildren, children);
}
return map(i);
});
}
/**
* 构建树结构
* @param treeList 展开的节点列表
* @param filterRoot 过滤根节点的策略
* @param idKey ID 属性名
* @param pidKey parentId 属性名
* @param childrenKey children 列表 属性名
* @param leaveEmptyChildren 是否保留空的子节点, 默认不保留
*/
static buildTree(treeList, filterRoot, idKey, pidKey, childrenKey, leaveEmptyChildren = false) {
if (ArrayTool.isEmpty(treeList)) {
return [];
}
// Id -> 节点映射
const mapping = treeList.reduce((pv, cv) => {
pv[cv[idKey]] = cv;
return pv;
}, {});
for (let node of treeList) {
const pid = node[pidKey];
if (pid === undefined) {
continue;
}
const pNode = mapping[pid];
if (pNode === undefined || pNode === null) {
continue;
}
if (ArrayTool.isEmpty(pNode[childrenKey])) {
pNode[childrenKey] = [];
}
pNode[childrenKey].push(node);
}
// @ts-ignore
let root = Object.values(mapping).filter(filterRoot);
if (!leaveEmptyChildren) {
root = ArrayTool.treeEach(root, i => {
if (ArrayTool.isEmpty(i[childrenKey])) {
delete i[childrenKey];
}
return i;
}, undefined, childrenKey);
}
return root;
}
}
//# sourceMappingURL=TreeTool.js.map