
本文介绍一种通用、递归的 javascript 方法,将包含层级路径(如分类数组)的扁平数据转换为符合 ui 组件(如 ant design tree 或 element plus cascader)要求的嵌套树形结构,支持任意深度与混合节点(目录+文档)。
本文介绍一种通用、递归的 javascript 方法,将包含层级路径(如分类数组)的扁平数据转换为符合 ui 组件(如 ant design tree 或 element plus cascader)要求的嵌套树形结构,支持任意深度与混合节点(目录+文档)。
在前端开发中,后端常以扁平数组形式返回带路径信息的数据(例如 category: ["Test", "Test 2", "Test 3"]),但前端组件(如树形选择器、文件浏览器)需要标准的嵌套树结构。核心挑战在于:既要正确还原多级目录层级,又要将终端数据(如文档)作为叶子节点插入对应路径末端——而非全部挂载为最深层子项。
以下是一个健壮、可复用的递归构建方案:
function buildTree(flatData, pathKey = 'category', valueKey = 'otherFields') {
const root = { label: 'root', children: [] };
const insert = (node, path, value) => {
if (path.length === 0) {
// 到达路径终点:插入实际内容(如文档)
node.children.push({ label: value });
return;
}
const [currentLabel, ...restPath] = path;
let childNode = node.children.find(child => child.label === currentLabel);
if (!childNode) {
childNode = { label: currentLabel, children: [] };
node.children.push(childNode);
}
insert(childNode, restPath, value);
};
flatData.forEach(item => {
const path = Array.isArray(item[pathKey]) ? item[pathKey] : [];
const value = Array.isArray(item[valueKey]) && item[valueKey].length > 0
? item[valueKey][0]
: String(item[valueKey] || '');
insert(root, path, value);
});
return root.children; // 去除虚拟根节点,返回真实树根列表
}
// 使用示例
const data = [
{ category: ["Kat1"], otherFields: ["Document 1"] },
{ category: ["Kat1"], otherFields: ["Document 2"] },
{ category: ["Test", "Test 2"], otherFields: ["Document 1"] },
{
category: ["Test", "Test 2", "Test 3", "Test 4", "Test 5", "Test 6", "Test 7", "Test 8", "Test 9", "Test 10", "Test 11"],
otherFields: ["Document 1"]
}
];
const tree = buildTree(data);
console.log(JSON.stringify(tree, null, 2));
✅ 关键设计说明:
- 路径驱动构建:每个 category 数组被视为一条从根到叶的路径,逐级创建中间节点;
- 统一叶子处理:当 path 为空时,将 otherFields[0] 作为纯文本标签插入,确保文档不被误建为目录;
- 防重与兼容:自动去重同名同级节点(如多个 "Kat1" 共享同一子节点容器);
- 健壮性增强:支持 pathKey/valueKey 自定义字段名,并对非数组或空值做安全兜底。
⚠️ 注意事项:
- 若需保留原始 otherFields 全量数据(不止第一个),可将 value 改为 { label: ..., data: item.otherFields };
- 如需支持排序(如按字母序排列同级节点),可在 insert 返回后对 node.children 调用 sort();
- 对超深嵌套(如 20+ 层),建议添加递归深度限制或改用栈式迭代实现以防栈溢出。
该方法时间复杂度为 O(n × d)(n 为数据项数,d 为平均路径长度),空间上仅需树结构本身内存,在万级数据下仍保持高效。无需依赖第三方库,可直接集成至 Vue/React/Angular 项目中作为工具函数复用。











