Vue 3 中用好 BEM 的关键是文件名—Block名—类名三者严格对齐:UserCard.vue 对应 user-card,SCSS 嵌套须守 BEM 规则,动态类名需静态可析,穿透样式须锚定 Block 或 Element。

Vue 3 单文件组件中用好 BEM,关键不是“加前缀”,而是建立文件名—Block名—类名三者严格对齐的硬约束。只要这根链条断了,IDE 跳转失效、stylelint 报错、新成员看不懂、样式意外泄漏,全都会跟着来。
组件文件名就是 Block 名的唯一来源
文件名决定 Block 名,不能缩写、不能意译、不能大小写混用:
- UserCard.vue → Block 名必须是 user-card(✅)
- UserCard.vue →
card、userCard、user__card都算错(❌) - SearchBar.vue → 只能是 search-bar,不是
searchbar或search-bar-comp - 重命名组件时,SCSS 中的
.user-card类必须同步改,否则语义链断裂
SCSS 嵌套必须守住 BEM 语法边界
BEM 不允许修饰符直接修饰元素,& 是字符串拼接器,不是语义理解器:
审查 Vue 管理后台的变更请求(Vue 2 + Element UI,Vue 3 + Element Plus)。重点关注最小化变更实现、上线风险检查以及回归检查清单生成。
- ✅ 安全写法:
.user-card { &--compact { padding: 8px; } &__header { color: #333; } } - ❌ 错误写法:
.user-card { &--compact { &__header { } } }→ 编译出.user-card--compact__header,违反 BEM - 修饰符作用于元素时,应写成
&__header--large,而非&__header &--large - 避免嵌套选择器如
.user-card .user-card__header,BEM 类名本身已含层级语义
动态类名必须静态可分析
Vue 的 scoped 样式依赖编译期静态解析,运行时拼接会绕过作用域控制:
立即学习“前端免费学习笔记(深入)”;
- ✅ 推荐:
:class="['user-card', isCompact && 'user-card--compact']" - ❌ 危险:
:class="'user-card--' + status"或:class="[baseClass, 'item--hover']"(baseClass 若不含完整前缀) - computed 返回类名时,必须返回完整字符串,如
'user-card__avatar',不能只返回'__avatar' - 用工具函数封装更稳妥,例如
cnUserCard({ compact: true })返回数组,交由clsx合并
穿透样式必须锚定在 BEM 容器内
::deep() 不是全局开锁钥匙,它必须被包裹在明确的 Block 或 Element 类名下:
- ✅ 正确:
.user-card__action-btn :deep(.el-button) { height: 32px; } - ❌ 错误:
:deep(.el-button)单独写在 scoped style 里,或.user-card :deep(.el-button)(层级太宽,可能误触子组件) - Teleport 渲染的内容脱离组件作用域,scoped 失效,此时应改用全局 BEM 类,且 Block 名需全局唯一

















