@diyaner/ding
Version:
dingiyan常用ts/js工具
257 lines • 9.21 kB
JavaScript
;
/*
* @copyright: ChengXuan
* @Author: ding
* @Date: 2022-08-13 09:23:13
* @LastEditors: ding
* @LastEditTime: 2022-09-12 11:39:30
* @Description: file content
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.TreeNode = exports.ListToTree = void 0;
class ListToTree {
constructor(
/** origin list */
originlist) {
/**
* in passing transacted to obj when to tree.
*
* the options.id is key.
*/
this.obj = {};
this.checkTheOriginList(originlist);
this.list = [...originlist];
}
/** 静态方法,实例化一个listToTree,并返回实例 */
static init(originList) {
return new ListToTree(originList);
}
setOption(opt) {
this.option = opt;
}
getOption() {
return this.option;
}
/**
* the main method. do turn list to tree.
*/
toTree(option) {
option && this.setOption(option);
this.checkParams();
this.option.allowEmptyChildren = this.option.allowEmptyChildren === false ? false : true;
/** 实现思路:先把列表按parent和id进行key value展平成对象 */
const parentField = this.option.parent;
const idField = this.option.id;
const rootValue = this.option.rootValue || 0;
const sortFunction = this.option.sort;
/** 以父级id为key的对象 值为子元素列表 */
const objp = {};
/** 以节点id为key的对象 值为元素对象 */
const objId = {};
for (const item of this.list) {
const parentId = item[parentField];
objp[parentId] = objp[parentId] || [];
objp[parentId].push(item);
objId[item[idField]] = item;
}
/** 根节点列表 */
const rootList = objp[rootValue] || [];
// 处理父id不存在的情况,改为将root作为父id 这样可以拿到断层的游离节点放入根位置
if (this.option.absentParentResetToRootValue) {
const ids = Object.keys(objId);
const pids = Object.keys(objp);
for (const pid of pids) {
if (ids.includes(pid) || pid.toString() === rootValue.toString())
continue;
rootList.push(...objp[pid]);
}
}
if (!rootList.length)
throw new Error(`rootValue ${rootValue} could not find node.`);
const tree = [];
const objNode = {};
/** 递归遍历 */
const recursion = (arr, isRoot) => {
if (sortFunction) {
arr = sortFunction(arr);
}
if (isRoot) {
for (const item of arr) {
this.option.itemHandler && this.option.itemHandler(item, undefined);
const nodeItem = new TreeNode(item, this.option);
objNode[nodeItem.id] = nodeItem;
tree.push(nodeItem);
nodeItem.level = 0;
nodeItem.parentIds = []; // top level's parent is empty.
nodeItem.parentNode = null;
if (objp[nodeItem.id]) {
recursion(objp[nodeItem.id], false);
}
}
}
else {
for (const item of arr) {
const parentItem = objNode[item[parentField]];
this.option.itemHandler && this.option.itemHandler(item, parentItem);
const nodeItem = new TreeNode(item, this.option);
objNode[nodeItem.id] = nodeItem;
parentItem.children = !!parentItem.children ? parentItem.children : [];
parentItem.children.push(nodeItem);
nodeItem.level = parentItem.level + 1;
nodeItem.parentIds = [nodeItem.parent, ...parentItem.parentIds];
nodeItem.parentNode = parentItem;
if (objp[nodeItem.id]) {
recursion(objp[nodeItem.id], false);
}
}
}
};
recursion(rootList, true);
this.obj = objNode;
this.tree = tree;
return tree;
}
/**
* get one node's level.
*
* top level is 0
* */
getLevel(id) {
const treeNode = this.obj[id];
if (treeNode == undefined) {
throw new Error(`your id is not found node object.`);
}
return treeNode.level;
}
/** get node's parents node id. */
getParentIds(id) {
const arr = this.obj[id];
if (arr == undefined) {
throw new Error(`your id ${id} cound not found on node object.`);
}
return arr.parentIds;
}
/** get all parents node object. */
getParentNodes(id) {
const arr = this.getParentIds(id);
return arr.map((nodeId) => this.obj[nodeId]);
}
getNode(id) {
const obj = this.obj[id];
if (obj == undefined) {
throw new Error(`your id ${id} cound not found on node object.`);
}
return obj;
}
/** 获取一个节点的所有后代子节点id列表 */
getAllChildrens(id) {
const result = Object.keys(this.obj).filter((item) => {
return this.obj[item].parentIds.includes(id);
});
return result;
}
/** remove one or multiple node by id */
removeNode(id) {
const idFieldName = this.option.id;
const removeIds = Array.isArray(id) ? id : [id];
const newList = this.list.filter((item) => !removeIds.includes(item[idFieldName]));
this.list = newList;
return this.toTree(this.option);
}
pushNode(obj) {
this.list.push(obj);
return this.toTree(this.option);
}
/** 检查源数据列表 */
checkTheOriginList(list) {
if (!Array.isArray(list)) {
throw new Error(`[${ListToTree.name}] the argument [list] require array.`);
}
}
/** 检查toTree的选项参数 */
checkParams() {
if (!this.option) {
throw new Error(`[${ListToTree.name}] the [option] is require.`);
}
this.checkTheOriginList(this.list);
if (!this.option.id || !["string", "number"].includes(typeof this.option.id)) {
throw new Error(`[${ListToTree.name}] the argument [option] require id field and it's must be stringNumber or number.`);
}
if (!this.option.parent || !["string", "number"].includes(typeof this.option.parent)) {
throw new Error(`[${ListToTree.name}] the argument [option] require parent field and it's must be stringNumber or number.`);
}
}
}
exports.ListToTree = ListToTree;
exports.default = ListToTree;
/** 树节点类 */
class TreeNode {
constructor(obj, option) {
/** 节点层级 */
this.level = 0;
/** 父节点id的数组 从父级一直到顶层 */
this.parentIds = [];
this.origin = obj;
this.option = option;
this.children = this.option.allowEmptyChildren ? [] : undefined;
}
/** node label 从源对象中映射 */
get label() {
return this.origin[this.option.mapToLabel || "label"];
}
/** node id 从源对象中映射 */
get id() {
return this.origin[this.option.id || "id"];
}
/** node value 从源对象映射,使用自定义map映射或id的映射 */
get value() {
return this.origin[this.option.mapToValue || this.option.id || "id"];
}
/** node parent id 从源对象中映射 的父节点id */
get parent() {
return this.origin[this.option.parent || "parent"];
}
/** 获取所有后代节点的id列表 */
getAllChildrensId() {
if (!this.children || this.children.length === 0)
return [];
const sonIds = [];
const afterSonIds = [];
for (const child of this.children) {
sonIds.push(child.id);
afterSonIds.push(...child.getAllChildrensId());
}
return [...sonIds, ...afterSonIds];
}
/** 获取所有后代节点对象 */
getAllChildrensNode() {
if (!this.children || this.children.length === 0)
return [];
const sonNodes = [];
const afterSonNodes = [];
for (const child of this.children) {
sonNodes.push(child);
afterSonNodes.push(...child.getAllChildrensNode());
}
return [...sonNodes, ...afterSonNodes];
}
/** 用于json序列化,去除循环引用,获取get属性 */
toJSON() {
const obj = {
id: this.id,
value: this.value,
parent: this.parent,
label: this.label,
level: this.level,
parentIds: this.parentIds,
origin: this.origin,
children: this.children,
};
if (!this.option.treeNodeToJson)
return obj;
const res = this.option.treeNodeToJson(obj, this);
return res;
}
}
exports.TreeNode = TreeNode;
//# sourceMappingURL=listToTree.js.map