Bootstrap 5 可用 collapse 插件实现树形菜单,通过嵌套 HTML 结构、data-bs-toggle/target 控制展开收起,配合 aria 属性保障可访问性,并用 CSS 伪元素旋转箭头图标;动态加载需手动初始化 Collapse 实例。

Bootstrap 本身不提供原生的 treeview 组件,官方 CSS 和 JS 都没实现树形菜单逻辑——你得靠第三方插件或手写递归渲染 + 折叠控制。
为什么直接用 Bootstrap 的 collapse 就能搭出基础树菜单
Bootstrap 5+ 的 collapse JS 插件支持嵌套、手动触发和事件监听,配合层级结构的 HTML(如 ul/li),就能实现展开/收起。不需要引入完整框架,避免样式冲突和体积膨胀。
- 每个子节点用
<div class="collapse"> 包裹其子 <code>ul,父li加data-bs-toggle="collapse"和对应data-bs-target - 必须为每个折叠容器设唯一
id,data-bs-target指向它(例如#menu-users) - Bootstrap 5 要求显式引入
bootstrap.bundle.min.js(含 Popper 和 collapse 依赖),否则点击无反应 - 别漏掉
aria-expanded和aria-controls—— 否则屏幕阅读器无法识别状态,WCAG 不达标
如何让箭头图标随展开状态自动翻转
纯 CSS 可控,不用 JS 切类名。关键在利用 .collapse.show 的存在与否,结合 ::before 伪元素旋转。
.tree-toggle::before {
content: "▶";
display: inline-block;
margin-right: 6px;
transition: transform 0.2s;
}
.collapse.show + .tree-toggle::before,
.tree-toggle[aria-expanded="true"]::before {
transform: rotate(90deg);
}
-
.collapse.show是 Bootstrap 插件添加的类,表示已展开;但注意它不在触发按钮上,而在被展开的内容容器里 - 所以更稳的方式是监听
aria-expanded属性变化,直接写在按钮选择器里(如.tree-toggle[aria-expanded="true"]) - 如果用了 SVG 图标,就改
transform: rotate(90deg);用 Font Awesome 则建议用fa-chevron-right/fa-chevron-down切换类名(需 JS 辅助)
动态加载子菜单时 collapse 不生效?检查这三点
异步插入 DOM 后,Bootstrap 的 collapse 实例不会自动绑定新元素 —— 它只初始化页面加载时已存在的节点。
- 手动初始化:插入 HTML 后调用
new bootstrap.Collapse(element, { toggle: false }) - 确保新插入的
<div class="collapse"> 有正确 <code>id,且对应按钮的data-bs-target值一致(比如data-bs-target="#menu-logs") - 避免重复初始化:对同一个
id多次调用Collapse会报错"Cannot instantiate collapse on element twice",加个data-bs-initialized标记判断
真正麻烦的是跨级联动(比如点父节点时自动收起其他同级展开项),这得自己监听 show.bs.collapse 事件并手动 hide() 其他实例 —— Bootstrap 不管这个逻辑,默认允许多开。别指望靠 class 名称规则自动处理,DOM 查询和状态管理得你来兜底。


















