为了将给定的扁平化菜单数组转换为嵌套树形结构,我们需要遍历数组并构建一个映射,以便我们可以根据parentId快速找到父节点。然后,我们可以再次遍历数组,将每个项目添加到其对应的父节点的children数组中(如果父节点存在)。
以下是一个简单的JavaScript函数,它实现了这种转换:
function flattenToTree(items) {
// 创建一个映射,用于快速查找具有给定id的节点
const map = new Map();
items.forEach((item) => map.set(item.id, { ...item, children: [] }));
// 遍历所有节点,如果它们有parentId,则将它们添加到其父节点的children数组中
items.forEach((item) => {
if (item.parentId) {
// 确保父节点存在
const parent = map.get(item.parentId);
if (parent) {
parent.children.push(map.get(item.id));
}
}
});
// 提取所有顶级节点(没有parentId的节点)
return [...map.values()].filter((item) => !item.parentId);
}
// 示例数据
const menuItems = [
{ id: 1, menu: "水果", level: 1 },
{ id: 2, menu: "橘子", level: 2, parentId: 1 },
// 可以添加更多菜单项...
];
// 调用函数并打印结果
const tree = flattenToTree(menuItems);
console.log(tree);
当你运行上述代码时,它应该输出类似于以下内容的树形结构:
[
{
"id": 1,
"menu": "水果",
"level": 1,
"children": [
{
"id": 2,
"menu": "橘子",
"level": 2,
"parentId": 1,
"children": []
}
// ... 其他子菜单项(如果有的话)
]
}
// ... 其他顶级菜单项(如果有的话)
]
请注意,这个函数假设id是唯一的,并且每个节点的parentId(如果存在)都引用了一个已存在的id。如果这不是情况,你可能需要添加额外的错误处理来避免未定义的行为。
当然,我们可以使用更多层次的数据来测试这个函数。以下是一个包含三个层次(顶级、一级子菜单、二级子菜单)的示例数据:
const menuItems = [
{ id: 1, menu: '食品', level: 1 },
{ id: 2, menu: '水果', level: 2, parentId: 1 },
{ id: 3, menu: '蔬菜', level: 2, parentId: 1 },
{ id: 4, menu: '柑橘类', level: 3, parentId: 2 },
{ id: 5, menu: '绿叶蔬菜', level: 3, parentId: 3 },
// 还可以继续添加更多菜单项...
];
// 使用前面定义的 flattenToTree 函数
const tree = flattenToTree(menuItems);
console.log(tree);
运行上述代码后,应该得到如下输出(格式化后的JSON结构):
[
{
"id": 1,
"menu": "食品",
"level": 1,
"children": [
{
"id": 2,
"menu": "水果",
"level": 2,
"parentId": 1,
"children": [
{
"id": 4,
"menu": "柑橘类",
"level": 3,
"parentId": 2,
"children": []
}
]
},
{
"id": 3,
"menu": "蔬菜",
"level": 2,
"parentId": 1,
"children": [
{
"id": 5,
"menu": "绿叶蔬菜",
"level": 3,
"parentId": 3,
"children": []
}
]
}
// ... 其他一级子菜单项(如果有的话)
]
}
// ... 其他顶级菜单项(如果有的话)
]
如你所见,flattenToTree 函数能够正确处理多层次的数据结构,并将其转换为嵌套的树形结构。每个节点都有一个 children 数组,用于包含其所有子节点。如果某个节点没有子节点,则其 children 数组将为空。