树形控件BEM组织核心是每个节点必须为独立tree-node块,不可用tree__node元素;缩进用data-level属性控制,禁止类名表达层级;图标状态用tree-node__icon--expanded等修饰符;复杂内容应升格为独立Block。

树形控件的 BEM 组织核心就一条:每个节点必须是独立 tree-node 块,不是 tree__node 元素。否则缩进、展开逻辑会随嵌套深度失控,维护时改一个 level 就得扫全量 HTML 类名。
为什么不能把整棵树塞进一个 tree 块里?
真实项目里最常踩的坑,就是写了个 tree__node,结果发现它依赖父级 tree__children 才能缩进或展开——这已经违背 BEM 的“块独立”原则。树形结构天然递归,但 BEM 要求每个可复用单元自包含。
-
tree-node是块,可单独渲染、测试、复用 -
tree-node__children只是布局容器,不带业务逻辑,也不控制子节点样式 - 子节点是另一个
tree-node实例,不是tree-node__node或tree-node__children__node - 一旦用后代选择器写
.tree__children .tree__node,DOM 深度一变,样式权重和稳定性全崩
缩进必须用 data-level 属性,别碰 --level-2 这类类名
缩进是视觉表现,不是语义层级。BEM 明确反对用类名表达“第几级”,因为树深度一变,HTML 就得批量改,CSS 也得跟着调。
- JS 渲染时给每个
tree-node添加data-level="2"属性 - CSS 用属性选择器控制:
.tree-node[data-level="0"] { padding-left: 0; }、.tree-node[data-level="1"] { padding-left: 24px; } - 避免
tree-node--level-2或tree-node--indent-2—— 这让 HTML 和 CSS 强耦合 - 也不推荐靠 DOM 层级推导,比如
:scope > .tree-node__children > .tree-node,不如data-level稳定
tree-node__icon 的状态修饰符必须挂载在元素上,不能反着来
图标不是独立组件,而是 tree-node 的一部分,所以命名必须落在块内:tree-node__icon,而不是 icon 或 tree-icon。它的状态(展开/收起/禁用)通过修饰符体现。
- ✅
tree-node__icon--expanded:图标自身的状态 - ❌
tree-node--expanded__icon:语法错误,BEM 不支持修饰符挂载在元素上 - ⚠️ 正交方案是组合使用:
tree-node--expanded控制整体展开态,tree-node__icon--expanded控制图标旋转或内容变化 - 禁止写成
tree-node--icon-expanded,这混淆了块与元素边界
复杂节点内容要升格为独立 Block,别硬套 __ 嵌套
当树节点里嵌了带操作栏的部门卡片、含头像和联系人的人员节,就说明它已超出“节点”职责边界。这时候继续用 tree-node__person-card 是在透支 BEM 的表达力。
- 应抽为独立 Block,如
person-card或department-panel - 它们通过
tree-node__content容器承载,但样式完全隔离 - 避免出现
tree-node__content__avatar这类三层嵌套,SCSS 里也不该写&__content { &__avatar {} } - 如果真需上下文感知(比如“在树里显示时 avatar 要小一圈”),用属性选择器更可控:
.tree-node[data-in-tree="true"] .person-card__avatar
真正难的不是写对第一个 tree-node,而是在第五层嵌套、二十个节点类型混排时,依然能一眼分辨哪个类名属于哪个职责边界。data-level 和独立块这两条线,断哪条都会让后续迭代变成修修补补的体力活。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











