直接用 classList.toggle('active') 在 SPA 中易出错,因泛化类名无上下文绑定,多组件共存时易选错元素,且 SSR 与客户端状态不同步会导致闪烁;button--disabled 必须与 disabled 属性同步更新以保障可访问性。

为什么直接用 classList.toggle('active') 在 SPA 里容易出事
因为 SPA 中组件可能被反复挂载/卸载,而 active 这种泛化类名没有上下文绑定,一旦多个同名组件(比如两个 TabList)同时存在,document.querySelector('.active') 就会拿错元素;更麻烦的是,服务端渲染(SSR)时若 HTML 已带 active,客户端 hydration 后 JS 再 toggle,可能造成状态不一致或闪烁。
button--disabled 必须和 disabled 属性同步更新
BEM 修饰符不是视觉装饰,而是语义状态的映射。只加 button--disabled 类却不设 disabled 属性,键盘用户仍能聚焦、回车触发,违反可访问性要求;反之,只设属性不加类,CSS 样式就失效。
- 正确做法:用 JS 同时操作 DOM 属性和 class
btn.disabled = true; btn.classList.add('button--disabled');- 监听状态变化时,优先读取
btn.disabled,再同步 class,而不是反过来 - 避免在 CSS 里写
.button--disabled:disabled—— 这是冗余且不可靠的组合
多状态共存时,classList 添加顺序不影响样式,但影响可读性
CSS 规则匹配不依赖 class 列表顺序,所以 button--primary button--loading 和 button--loading button--primary 效果完全一样。但人要读代码,尤其调试时。
- 推荐顺序:基础类型 → 交互状态 → 尺寸/主题变体,例如:
button--primary button--loading button--small - 禁止把多个修饰符拼成一个,如
button--primary-loading—— 这已不是 BEM,而是新块名,破坏了语义层级 - JS 中用
classList.add()分开调用,别手动拼字符串:el.className = 'button button--primary button--loading'容易覆盖已有类
SSR 场景下,button--loading 类必须和服务端输出一致
如果服务端渲染时按钮是空闲态,但客户端 JS 立即加上 button--loading,就会出现“闪动”——先显示正常按钮,再跳变成加载态。这不是动画问题,是状态不同步。
- 服务端需根据当前数据状态决定是否输出
button--loading - 客户端初始化时,先检查 DOM 上已有类,再决定是否触发 loading 流程
- 不要假设“页面一进来就要 loading”,很多状态应由用户动作触发,而非自动启动
真正难的不是写对 button--disabled,而是让每个开发者在添加新状态时,都记得去翻组件文档、查已有修饰符命名、确认是否需要同步属性或 SSR 输出——BEM 的约束力,只在全员遵守时才生效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











