可直接用原生html+css+js实现语义化树状菜单:html须用嵌套ul/li结构,js通过事件委托切换子ul.hidden状态,css用margin-left缩进并用伪元素控制箭头,首次渲染需js显式设hidden。

直接用原生 HTML + CSS + JavaScript 就能实现可展开/收起的树状目录菜单,不需要框架或第三方库。关键在于结构语义正确、事件绑定精准、CSS 控制显示状态,而不是堆砌 class 或依赖 jQuery。
HTML 结构必须用 ul/li 嵌套,不能用 div 模拟
浏览器和屏幕阅读器依赖语义化列表识别层级关系。ul 表示无序目录,每个子目录用嵌套 ul,父 li 同时包裹标题和子列表。错误写法(如纯 div 套 div)会导致键盘导航失效、无法被辅助技术识别。
正确结构示例:
-
? 文档
- README.md
- CHANGELOG.md
-
? src
- main.js
- utils/
-
ul.tree是根容器,所有交互逻辑基于它 - 每个可折叠项的触发元素(如
span.toggle)必须是li的直接子元素,且紧邻子ul - 子
ul默认不设display: none,靠 JS 切换hidden属性更稳妥
toggle 点击事件必须委托到 ul.tree,不能逐个绑定
动态生成的目录项(比如从 API 加载)会频繁增删,逐个 addEventListener 容易内存泄漏或漏绑。委托到根 ul 一劳永逸。
将调研报告、方案对比、数据分析、需求梳理、会议纪要、设计说明、代码评审、学习笔记等任务产物输出为可在浏览器直接打开的单文件 HTML,替代 Markdown 作为最终交付物。Markdown 在信息密度、视觉清晰度和可分享性上已跟不上 AI 产物的丰富度,HTML 能同时承载排版、表格、SVG 等。
实操要点:
- 监听
ul.tree的click事件,用event.target.matches('.toggle')判断是否点中开关 - 通过
event.target.nextElementSibling获取紧邻的子ul,避免用querySelector查找造成性能波动 - 切换时优先用
element.hidden = !element.hidden,比操作className更轻量、无样式耦合
简短逻辑示例:
document.querySelector('ul.tree').addEventListener('click', e => {
if (e.target.matches('.toggle')) {
const next = e.target.nextElementSibling;
if (next && next.tagName === 'UL') {
next.hidden = !next.hidden;
}
}
});
CSS 需隐藏默认箭头并控制缩进,避免用 display: none 影响布局计算
用 hidden 属性隐藏子列表后,CSS 要确保视觉缩进与层级匹配,同时保留可访问性。
- 给
.tree ul设margin-left: 1.5em实现缩进,不要用padding-left(影响点击热区) - 用
.toggle::before伪元素显示 ▶ / ▼,配合ul[hidden] + .toggle::before反转箭头,比 JS 操作 class 更干净 - 禁用
ul.tree ul { display: none; }这类写法——它会让offsetHeight返回 0,后续做动画或计算高度时出错
真正容易被忽略的是:子列表首次渲染时,hidden 属性必须由 JS 显式设置(比如遍历所有子 ul 并设 hidden=true),不能只靠 CSS 隐藏。否则初始状态不一致,用户刷新页面后可能看到全部展开。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










