[TypeScript] 将一个列表转为树形列表的函数(通用型)
今天分享一个自己实现的基于 TypeScript 的将列表转为树形列表的通用函数。
/**
* 将一个列表转化为树形列表, 列表数据需要本身支持转化成数型
* @param list 列表数据
* @param equalLevalItem 判断两个列表项是否同级且不相等的回调函数
* @param listFirstIsRoot 使用列表中的第1项作为树的root节点
* @param isRootItem 判断列表项是否为root节点的回调函数,listFirstIsRoot = false 时有效
* @param childrenField 列表项中,存放 children 列表的字段名称
* @param childrenMust 子列表字段是否必须存在,为 true 时,如果没有子列表,会将其设置为 []
* @param item 当前列表项, 调用者传 undefined
* @returns
*/
// eslint-disable-next-line max-params
static toTreeList<T>(
list?: T[],
equalLevalItem?: (a: T | undefined, item: T) => boolean,
listFirstIsRoot: boolean = true,
isRootItem?: (e: T, index: number) => boolean,
childrenField: string = "children",
childrenMust: boolean = false,
item?: T,
): T[] {
const children: T[] = []
if (! list || list.length === 0) {
return children
}
const handleChildren = (e: T) => {
let srcData = e[childrenField];
if (childrenMust && ! srcData) {
srcData = []
e[childrenField] = srcData
}
const data: T[] | undefined = srcData ? srcData as T[] : []
data.push(...this.toTreeList(list, equalLevalItem, listFirstIsRoot, undefined, childrenField, childrenMust, e))
if (! srcData && data.length > 0) {
e[childrenField] = data;
} else if (data.length === 0 && ! childrenMust) {
e[childrenField] = undefined
}
}
let v = item
if (v === undefined) {
if (listFirstIsRoot) {
v = list[0]
if (v[childrenField] === undefined) {
v[childrenField].children = []
}
handleChildren(v)
children.push(v)
} else {
// 找出 root 项
list.forEach((e, index) => {
if (isRootItem?.(e, index)) {
handleChildren(e)
children.push(e)
}
})
}
return children
}
list.filter((e) => {
if (equalLevalItem?.(item, e)) { return e } // 排除掉当前 item
}).forEach((e) => {
handleChildren(e)
children.push(e)
})
return children
}
使用示例:
Utils.toTreeList(
list,
(src, item) => src?.id === item.pid && src.id !== item.id,
false,
(item, idx) => item.pid === 0
)