如何在JavaScript中递归实现菜单及多级子菜单的动态渲染?
递归渲染多层导航菜单的实现方案
这问题我之前做后台管理系统的时候经常碰到,多层嵌套的菜单用递归处理是最优雅的方式,核心思路就是判断每个菜单项是否包含子菜单,有就递归调用渲染函数/组件。下面我给你两种常见场景的实现示例,你可以按需选用:
一、原生JavaScript(纯DOM操作)
如果你的项目没有用框架,直接用原生JS就能搞定。我们可以写一个递归函数,负责把菜单数据转换成DOM元素:
// 递归渲染菜单的函数 function renderMenuItems(menuItems, parentElement) { menuItems.forEach(item => { // 创建菜单项容器 const menuItem = document.createElement('li'); menuItem.classList.add('menu-item'); // 创建菜单项标题 const title = document.createElement('a'); title.textContent = item.title; title.href = '#'; // 可以根据实际需求设置跳转链接 menuItem.appendChild(title); // 如果有子菜单,递归渲染 if (item.submenus && item.submenus.length > 0) { const subMenu = document.createElement('ul'); subMenu.classList.add('submenu'); // 递归调用,把子菜单数据和当前子菜单容器传进去 renderMenuItems(item.submenus, subMenu); menuItem.appendChild(subMenu); } parentElement.appendChild(menuItem); }); } // 初始化渲染 const menuContainer = document.getElementById('menu-container'); const menuData = [ { title: "menu 1", submenus: [ { title: "sub menu1" }, { title: "sub menu2", submenus: [ { title: "subsub menu1", submenus: [ { title: "susubsub menu1" } ] }, { title: "subsub menu2" } ] } ] }, { title: "menu 2" } ]; renderMenuItems(menuData, menuContainer);
对应的基础CSS(可选,用来区分层级):
.menu-item { margin: 8px 0; list-style: none; } .submenu { margin-left: 20px; padding-left: 0; }
二、React组件实现(更适合现代前端项目)
如果用React的话,递归组件会更简洁,我们可以拆分出Menu和MenuItem两个组件:
import React from 'react'; // 子菜单组件,递归调用自身 const Menu = ({ items }) => { if (!items || items.length === 0) return null; return ( <ul className="menu-list"> {items.map((item, index) => ( <MenuItem key={index} item={item} /> ))} </ul> ); }; // 单个菜单项组件 const MenuItem = ({ item }) => { return ( <li className="menu-item"> <a href="#" className="menu-title">{item.title}</a> {/* 如果有子菜单,递归渲染Menu组件 */} {item.submenus && <Menu items={item.submenus} />} </li> ); }; // 使用示例 const App = () => { const menuData = [ { title: "menu 1", submenus: [ { title: "sub menu1" }, { title: "sub menu2", submenus: [ { title: "subsub menu1", submenus: [ { title: "susubsub menu1" } ] }, { title: "subsub menu2" } ] } ] }, { title: "menu 2" } ]; return <Menu items={menuData} />; }; export default App;
关键说明
- 递归的终止条件:当菜单项没有
submenus或者submenus为空数组时,就不会继续递归,只会渲染当前菜单项的标题。 - 如果需要添加展开/收起功能,可以给
MenuItem加一个状态(比如isExpanded),点击标题时切换状态,控制子菜单的显示隐藏(用CSS的display: none或者React的条件渲染)。 - 实际项目中,建议给每个菜单项加唯一的
key(不要用index,最好用后端返回的id),避免React渲染警告。
内容的提问来源于stack exchange,提问作者Devmasta
相关产品推荐
相关产品推荐

