如何实现支持无限子菜单的递归菜单生成函数?MongoDB场景遇问题
递归生成层级菜单问题
需求说明
实现一个递归函数,生成层级菜单结构:
- 当菜单项的
relatedId(父ID引用)未定义时,作为主菜单 - 当某菜单项的
id与另一项的relatedId匹配时,作为对应父菜单的子菜单
最终生成可无限扩展的层级JSON结构。
现有代码(无法正常运行)
const getMastersMenu = await Menu.find() let MenuArray: any = [] let SubMenuArray : any = [] getMastersMenu.map((menu: any) => { MenuArray.push({id: menu._id.toString(), name : menu.name, relatedId : menu?.relatedId}) }) const findRecursiveMenus = (menuItems: any) => { if (menuItems) { let newList: any = []; menuItems.map((menu: any) => { const findRelationship = menuItems.some((el: any, i: any) => { return el.id === menu.relatedId }) console.log(findRelationship) if(menu.relatedId === undefined){ let ObjectSubmenu = {id: menu.id, name : menu.name} newList.push(ObjectSubmenu) } else if (findRelationship){ let returnedList = findRecursiveMenus({submenus : {id: menu.id, name : menu.name, relatedId : menu.relatedId}}) newList.push(returnedList) } }) return newList; } }
代码问题分析
- 递归传参错误:递归调用时传入单个对象而非子项数组,导致无法遍历子菜单
- 父节点判断逻辑颠倒:
findRelationship仅判断当前菜单的父节点是否存在,未处理当前菜单作为父节点的子项 - 缺少子菜单容器:主菜单对象未添加
submenus属性,无法挂载子菜单 - 效率低下:每次遍历用
some查找,重复遍历导致时间复杂度高
修正后的代码
// 获取并转换菜单数据,确保ID类型统一 const getMastersMenu = await Menu.find(); const menuItems = getMastersMenu.map(menu => ({ id: menu._id.toString(), name: menu.name, relatedId: menu?.relatedId?.toString() // 统一为字符串类型,匹配id格式 })); // 构建ID映射表,快速查找子项 const menuIdMap = new Map(menuItems.map(item => [item.id, item])); // 递归生成层级菜单 const buildHierarchicalMenu = (parentId: string | undefined) => { // 筛选当前父节点下的所有子项 const childItems = menuItems.filter(item => item.relatedId === parentId); // 给每个子项递归生成自身的子菜单 return childItems.map(item => ({ ...item, submenus: buildHierarchicalMenu(item.id) })); }; // 生成最终的层级菜单(主菜单为relatedId未定义的项) const finalMenu = buildHierarchicalMenu(undefined); console.log(finalMenu);
代码说明
- ID映射优化:用
Map存储菜单ID与对应对象,避免重复遍历查找,提升处理效率 - 递归逻辑清晰:
buildHierarchicalMenu接收父ID,筛选对应子项后递归生成子菜单,结构层级明确 - 类型统一:将
relatedId转为字符串,确保和id类型匹配,避免因类型差异导致的匹配失败 - 结构统一:每个菜单项自动生成
submenus属性,无子项时为空数组,输出结构规范可扩展
内容的提问来源于stack exchange,提问作者Breno Sobral
相关产品推荐
相关产品推荐

