列表页不能只用一个 list Block,因BEM禁止Element嵌套Element、权限与样式耦合、批量浮层被截断;须拆为table-list、list-action-bar、list-item-actions等独立Block。

后台管理系统列表页不是“套个 class 就完事”的场景,直接用 .list__item 套到底,很快会卡在权限态、多操作列、行内编辑、批量操作浮层这些真实需求上——BEM 要起作用,得先按交互边界切块,而不是按 DOM 层级套名。
为什么列表页不能只用一个 list Block
常见错误是定义 .list,然后所有内容都塞进 .list__header、.list__body、.list__item、.list__item__action……这违反 BEM 三层结构限制,也掩盖了真实职责分离:
-
.list__item__action是非法命名:BEM 禁止 Element 嵌套 Element,__action必须属于某个 Block,而它实际是独立可复用的操作按钮组 - 权限控制常作用于整行(如“删除”按钮是否渲染),但
.list__item自身不持有权限逻辑,硬塞进去会让 JS 状态和 CSS 类名耦合 - 批量操作浮层(如“已选 3 项”提示条)需要脱离列表容器定位,若强行挂
.list__bulk-bar,z-index 和 position 会被父级.list的 overflow 或 transform 截断
哪些部分必须拆成独立 Block
后台列表页中真正该作为顶层 Block 存在的,是具备明确数据源、独立交互逻辑、可跨页面复用的单元:
-
table-list:负责表格骨架、分页器、顶部工具栏(含搜索、刷新、新建),但不含具体列渲染逻辑;列配置由 JS 控制,CSS 只管table-list__thead、table-list__pagination -
list-action-bar:批量操作浮层,固定在视口底部或右下角,用list-action-bar__counter、list-action-bar__btn,与table-list无样式依赖 -
list-item-actions:每行右侧操作列,含“编辑”“删除”“复制”等按钮,支持list-item-actions--readonly修饰符,内部按钮复用btnBlock -
list-filter-panel:高级筛选抽屉,独立控制展开/收起动画、表单校验、重置逻辑,不和table-list共享类名前缀
Modifier 该怎么用才不翻车
列表页状态多(加载中、空数据、权限不足、编辑态),Modifier 不是万能贴纸,用错位置会放大维护成本:
立即学习“前端免费学习笔记(深入)”;
- 禁止给 Block 加布局类:
.table-list--compact合理(影响行高、字体大小),但.table-list--sticky-header就越界了——sticky 是定位行为,应由table-list__header自己通过table-list__header--sticky控制 - 状态修饰符必须可叠加且无副作用:
.list-item-actions--disabled应仅禁用按钮,不改opacity或height;避免写.list-item-actions--disabled { display: none; },否则 JS 切换时 DOM 结构不稳定 - 权限态不要靠 Modifier 驱动显示隐藏:不用
.list-item-actions--no-delete控制按钮显隐,而是让 JS 根据权限字段决定是否渲染list-item-actions__btn--delete元素本身
和 React/Vue 组件怎么对齐
BEM 类名不是字符串拼接游戏,要和组件生命周期、状态管理对齐:
- 在 React 中,
table-list组件的根元素 className 应只挂table-list,所有子 Block(如list-filter-panel)由独立子组件渲染,不靠 props 传类名前缀 - 避免在组件里写
className={`${styles['table-list__item']} ${isActive ? styles['table-list__item--active'] : ''}`—— 改用clsx或直接拆成table-list__item table-list__item--active字符串,保持类名可读性 - 行内编辑状态(如点击某单元格进入输入框)不应靠
.table-list__cell--editing切换,而应由editable-cell这个新 Block 承载,它有自己的editable-cell__input和editable-cell__preview,与table-list解耦
最易被忽略的一点:后台列表页的“空状态”不是视觉装饰,而是独立交互入口。它必须是 empty-state Block,而不是 .table-list__empty —— 因为同一个空态组件可能复用于搜索无结果、权限拦截、数据加载失败等多个上下文,类名一旦绑定到 table-list,就锁死了复用路径。


















