JavaScript树形菜单折叠展开的核心是通过CSS类或display控制节点可见性并维护展开状态。实现包括:1.嵌套数据结构与语义化HTML;2.递归渲染DOM并绑定toggle事件;3.切换display和按钮符号,可选手风琴效果;4.支持localStorage持久化、ARIA属性和键盘操作。

JavaScript 实现树形菜单的折叠与展开,核心在于控制节点的可见状态(通常通过 CSS 类切换或直接操作 style.display),并维护节点的展开/折叠状态。下面是一个轻量、可复用、不依赖框架的实现方式。
1. 结构准备:HTML 与数据格式
树形菜单的数据建议使用嵌套数组或对象表示,每个节点包含 label(显示文字)、children(子节点数组,可为空)和可选的 expanded(初始展开状态,默认 false):
[
{
label: "文档管理",
expanded: true,
children: [
{ label: "新建文档" },
{ label: "打开最近", children: [{ label: "报告.docx" }, { label: "笔记.md" }] }
]
},
{ label: "设置", children: [{ label: "通用" }, { label: "外观" }] }
]
对应 HTML 使用语义化结构(如 <ul><li>),每个可展开节点添加一个折叠按钮(如 <span class="toggle">▶</span>),并为子列表设置唯一 class(如 submenu)便于控制显隐。
2. 渲染函数:递归生成 DOM
写一个递归渲染函数,根据数据生成带交互能力的 DOM:
立即学习“Java免费学习笔记(深入)”;
- 遇到有
children的节点,插入<span class="toggle">按钮,并默认用display: none隐藏子<ul>(若expanded: true则设为block) - 为每个
.toggle绑定点击事件,调用toggleNode函数 - 保持节点引用或使用 data 属性(如
data-index)关联 DOM 与数据,方便后续状态同步
3. 折叠/展开逻辑:单节点控制 + 递归联动
点击时切换当前节点的展开状态,并更新 UI:
- 查找紧邻的下一个
<ul class="submenu"> - 若存在,切换其
display值:none ↔ block(推荐加 CSS 过渡更平滑) - 同时更新按钮符号:如
▶ → ▼(可用textContent或 CSS 类控制) - 若需“展开时自动收起同级其他节点”(手风琴效果),则在展开前遍历父级下的所有兄弟
.submenu并隐藏
4. 进阶建议:状态持久化与可访问性
提升实用性的小细节:
- 用
localStorage记录用户最后的操作(如展开的路径),刷新后恢复 - 为
.toggle添加role="button"和aria-expanded属性,支持屏幕阅读器 - 键盘支持:监听
Enter或Space键触发相同行为 - 避免内联样式,用 CSS 类(如
.collapsed/.expanded)统一控制,利于主题切换
不复杂但容易忽略的是状态同步——DOM 显示状态和 JS 数据状态要一致,尤其在动态增删节点或批量操作时。保持单一数据源(如一个 treeData 对象),所有 UI 更新都基于它驱动,能大幅降低维护成本。


















