跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

如何利用 数组转树 (Array to Tree):处理后端返回的扁平菜单数据

将扁平菜单转为树形结构需两次遍历:首次用对象缓存节点并初始化children,识别根节点;第二次将非根节点挂载到父节点children下,时间复杂度O(n)。 后端返回的菜单数据通常是扁平结构的数组,每个对象带
id
、
parentId
(或
pid
)、
name
等字段。要渲染侧边栏、导航栏或树形选择器,需将其转为嵌套的树形结构。核心思路是:**用 Map 或对象缓存所有节点,再遍历一次,把子节点挂到对应父节点的
children
数组下**。 识别根节点并建立映射表 先遍历一次原始数组,区分根节点(如
parentId === null
、
parentId === 0
或
parentId === undefined
)和普通节点。同时用 JavaScript 对象(或
Map
)以
id
为键缓存每个节点,方便后续快速查找父节点: 推荐用普通对象
{}
,键为字符串化
id
(如
map[item.id] = item
),简单高效 注意检查
parentId
的实际值——有些接口用
"0"
字符串,有些用数字
0
,有些用
null
,需统一判断逻辑 给每个节点初始化空
children: []
,避免后续 push 时报错 单次遍历挂载子节点 再次遍历数组,对每个节点: 若它是根节点(如
!item.parentId || item.parentId === '0' || item.parentId === 0
),推入结果数组 否则,查出其父节点(
map[item.parentId]
),将当前节点
push
到父节点的
children
中 这个过程不递归、不嵌套循环,时间复杂度稳定为 O(n),适合千级以内菜单数据。 处理多级与排序需求 如果菜单要求按层级顺序展示(如一级菜单在前,其子菜单紧随其后),可在生成树后做一次 DFS 遍历展平并记录层级;若需前端控制展开/选中状态,建议在转换时就注入额外字段,例如:
level: 0
表示根,每深入一层 +1
path: ['1', '5', '12']
记录从根到当前节点的 id 路径,便于高亮或定位
isLeaf: !item.children?.length
标记是否为叶子节点,简化模板判断 兼容性与边界情况提醒 真实项目中常见坑点: 数据存在环引用(A 的 parent 是 B,B 的 parent 是 A)——转换前可加深度限制或 visited 集合检测 父节点在数组中出现在子节点之后——没关系,因为用的是映射表查找,不是顺序依赖 id 或 parentId 类型不一致(字符串 vs 数字)——建议统一转为字符串比较,或使用宽松相等
==
(但需确认业务允许) 后端返回空数组或 null —— 转换函数开头加守卫:
if (!Array.isArray(list) || list.length === 0) return []

相关文章