级联选择器的BEM类名必须拆分为cascader和dropdown两个独立Block,因二者职责分离、复用场景不同;错误命名如cascader__panel破坏Block独立性,正确结构为cascader内嵌dropdown实例。

级联选择器(Cascader)的 BEM 类名必须拆成 cascader 和 dropdown 两个独立 Block,不能出现 cascader__dropdown 或 cascader__menu 这类跨块命名——这是绝大多数项目踩坑的起点。
为什么 cascader 和 dropdown 必须是两个 Block
因为 Cascader 的核心职责是“控制级联逻辑、数据流转和触发行为”,而 dropdown 负责“面板定位、过渡动画、键盘导航、焦点管理”。二者语义分离、复用场景不同:同一个 dropdown 可能被 select、date-picker 复用;同一个 cascader 也可能在无下拉面板的精简模式中只渲染触发按钮。
- 错误写法:
cascader__panel、cascader__menu__item——把 UI 容器当成子元素,破坏 Block 独立性 - 正确结构:外层是
cascader,内部直接嵌套一个dropdown实例,如<div class="cascader"><div class="dropdown"></div></div> - DOM 必须紧邻或同父包裹,否则
.dropdown__menu的 hover 或 JS 显隐会失效(Vue<transition>或 React<Fragment>会插断兄弟关系)
cascader__trigger 和 cascader__input 怎么区分
cascader__trigger 是交互入口(可点击区域),cascader__input 是纯展示容器(只读文本),二者语义不同、交互逻辑不同,不能合并为一个类名。
-
cascader__trigger应支持focus、click、keydown,并挂载cascader__trigger--focused等修饰符 -
cascader__input只负责渲染选中路径,如浙江 / 杭州 / 西湖区,不响应用户输入 - 若需禁用状态,统一用
cascader--disabled,而不是给 trigger 或 input 单独加--disabled——Modifier 应作用于 Block 层级
多级菜单的 item 如何命名才不爆炸
不存在“三级菜单项”这种东西。BEM 不允许 cascader__menu__item__subitem,所有菜单层级都由嵌套的 dropdown 实例承担。
立即学习“前端免费学习笔记(深入)”;
- 一级菜单项:
dropdown__item(属于第一层 dropdown) - 二级菜单项:
dropdown__item(属于第二层 dropdown,嵌在上层dropdown__menu内) - 差异靠 Modifier 区分:
dropdown--level-2、dropdown--mega,而非靠父类前缀模拟层级 - 如果某类 item 需要独立样式(如带图标、带复选框),应升格为独立 Block:
checkbox-item或icon-label,而不是塞进cascader__item__icon
如何处理展开态、加载中、空状态等运行时类名
这些不是 BEM 的 Modifier,而是运行时状态类,必须和 BEM 类名解耦,避免混用。
- 禁止:
cascader__trigger--loading、cascader--expanded——--expanded是临时 DOM 状态,不是设计变体 - 推荐方案:用
is-前缀的状态类,如is-loading、is-expanded,配合 JS 控制显隐 - CSS 中写
.cascader.is-expanded .cascader__trigger,而不是依赖.cascader--expanded——这样既保持 BEM 结构纯净,又让状态切换可预测、可调试 - 工具链建议:用 stylelint 配置
selector-bem-pattern拦截--expanded类名,CI 阶段报错
最易被忽略的一点:BEM 类名是否合法,不取决于它“看起来像不像”,而取决于它能否在不看 HTML 的前提下,让人准确说出“这个类属于哪个组件、是它的哪部分、处于什么设计变体”。cascader__menu__item 看似顺理成章,但一问“menu 是 cascader 的子部件,还是另一个独立功能单元?”,答案就暴露了问题本质。


















