JavaScript 树形结构与列表结构的灵活转换:listToTree
与 treeToList
函数详解
在前端开发的数据处理工作中,树形结构和列表结构是两种常见的数据形式。树形结构能够清晰展示数据间的层级关系,适合用于菜单、组织架构等场景;而列表结构则更加简洁,方便存储和传输数据。为了满足不同场景下的数据处理需求,我们常常需要在这两种结构之间进行转换。本文将深入介绍两个实用的 JavaScript 函数 listToTree
和 treeToList
,它们能够帮助我们实现树形结构与列表结构的灵活转换,同时支持自定义关键属性名。
1. listToTree
函数:列表转树形结构
1.1 功能概述
listToTree
函数的核心功能是将一个扁平的列表数据转换为树形结构。该列表中的每个元素都包含一个唯一标识和一个父节点标识,通过这两个标识可以确定元素之间的层级关系。并且,该函数支持用户自定义这些标识的属性名,增强了函数的通用性。
1.2 函数定义与实现
javascript
// 假设 getConfig 函数用于合并默认配置和用户传入的配置
function getConfig(config) {
const defaultConfig = {
id: 'id',
children: 'children',
pid: 'pid'
};
return { ...defaultConfig, ...config };
}
// tree from list
export const listToTree = <T = any>(list: any[], config: Partial<TreeHelperConfig> = {}): T[] => {
const conf = getConfig(config) as TreeHelperConfig;
const nodeMap = new Map();
const result: T[] = [];
// 动态获取配置中的属性名
const idKey = conf.id;
const childrenKey = conf.children;
const pidKey = conf.pid;
for (const node of list) {
// 动态设置 children 属性
node[childrenKey] = node[childrenKey] || [];
nodeMap.set(node[idKey], node);
}
for (const node of list) {
const parent = nodeMap.get(node[pidKey]);
// 根据动态属性名操作节点
(parent ? parent[childrenKey] : result).push(node);
}
return result;
};
// 定义 TreeHelperConfig 类型
type TreeHelperConfig = {
id: string;
children: string;
pid: string;
};
// 这里 Partial 表示配置中的属性都是可选的
type Partial<T> = {
[P in keyof T]?: T[P];
};
1.3 使用方法
- 参数说明 :
list
:必需,待转换的扁平列表数据。列表中的每个元素应包含唯一标识和父节点标识。config
:可选,配置对象,用于自定义关键属性名。包含以下属性:id
:节点的唯一标识属性名,默认为id
。children
:存储子节点的属性名,默认为children
。pid
:父节点标识属性名,默认为pid
。
1.4 示例
假设我们有如下自定义属性名的扁平列表数据:
javascript
const flatList = [
{ uniqueId: 1, name: '总公司', parentId: null },
{ uniqueId: 2, name: '研发部', parentId: 1 },
{ uniqueId: 3, name: '前端组', parentId: 2 },
{ uniqueId: 4, name: '张三', parentId: 3 },
{ uniqueId: 5, name: '李四', parentId: 3 },
{ uniqueId: 6, name: '后端组', parentId: 2 },
{ uniqueId: 7, name: '王五', parentId: 6 },
{ uniqueId: 8, name: '市场部', parentId: 1 },
{ uniqueId: 9, name: '推广组', parentId: 8 },
{ uniqueId: 10, name: '赵六', parentId: 9 }
];
// 转换为树形结构,指定自定义的属性名
const tree = listToTree(flatList, { id: 'uniqueId', children: 'subNodes', pid: 'parentId' });
console.log(tree);
在上述示例中,我们通过传入自定义的属性名 uniqueId
、subNodes
和 parentId
,成功将扁平列表转换为树形结构。
2. treeToList
函数:树形结构转列表
2.1 功能概述
treeToList
函数的作用是将树形结构数据转换为扁平的列表结构。它会遍历树形结构中的每个节点,并将其添加到一个列表中,同样支持用户自定义存储子节点的属性名。
2.2 函数定义与实现
javascript
export const treeToList = <T = any>(tree: any, config: Partial<TreeHelperConfig> = {}): T => {
const conf = getConfig(config);
// 动态获取配置中的 children 属性名
const childrenKey = conf.children;
const result: any = [...tree];
for (let i = 0; i < result.length; i++) {
if (!result[i][childrenKey]) continue;
// 根据动态属性名展开子节点
result.splice(i + 1, 0, ...result[i][childrenKey]);
}
return result;
};
2.3 使用方法
- 参数说明 :
tree
:必需,待转换的树形结构数据。config
:可选,配置对象,用于自定义存储子节点的属性名。包含以下属性:children
:存储子节点的属性名,默认为children
。
2.4 示例
使用前面转换得到的树形结构数据,将其转换回扁平列表:
javascript
// 再将树形结构转换回列表
const backToList = treeToList(tree, { children: 'subNodes' });
console.log(backToList);
在这个示例中,我们传入自定义的 children
属性名 subNodes
,成功将树形结构转换回扁平列表。
总结
通过 listToTree
和 treeToList
这两个函数,我们可以方便地在树形结构和列表结构之间进行转换,并且能够根据实际需求自定义关键属性名。这大大提高了代码的灵活性和通用性,使得我们能够更好地应对不同场景下的数据处理需求。在实际开发中,你可以根据具体的数据结构和业务需求,灵活运用这两个函数,实现高效的数据转换和处理。