date-picker__panel 只能是 Element,不能当 Block 用;calendar-grid、year-selector、month-selector、dropdown 才是独立 Block,各自遵循 BEM 规范并解耦状态逻辑。

date-picker__panel 不能当 Block 用
它只是容器壳,不是独立功能单元。真正承担日历渲染、日期交互、状态响应的是 calendar-grid,所以 date-picker__panel 只能是 date-picker 的一个 Element,内部必须嵌套独立的 calendar-grid Block。
常见错误是把整个弹层写成 date-picker__calendar__day——这违反 BEM 最基本规则:Element 不允许嵌套 Element(双下划线只出现一次),更致命的是锁死了 calendar-grid 的复用能力。
-
date-picker__panel负责绝对定位、z-index、阴影、进出动画等“弹层通用行为” -
calendar-grid负责日历本体:格子生成、周头渲染、日期状态标记(calendar-grid__day--today、calendar-grid__day--disabled) - 年份/月份切换控件也得拆成独立 Block:
year-selector和month-selector,不能塞进date-picker__header里
日期状态类名必须挂 calendar-grid__day 上
“今天”“已选中”“不可选”这些不是视觉修饰,而是数据驱动的状态,必须由 JS 显式控制,并且只能挂在 calendar-grid__day 这一层。用伪类 :disabled 或 :checked 是无效的——DOM 是自定义的,浏览器不识别语义。
-
calendar-grid__day--today:仅表示语义上的“今日”,不带交互逻辑 -
calendar-grid__day--selected:JS 切换,支持叠加(如多选范围的calendar-grid__day--range-start) -
calendar-grid__day--disabled:基于 min/max 或业务规则禁用,CSS 只管opacity和pointer-events: none - 别在
date-picker__trigger上加--has-value以外的状态——它的职责只是响应点击和回显文本
year-selector 和 month-selector 必须是独立 Block
它们不是 date-picker 的子元素,而是有自己焦点管理、键盘导航、展开收起逻辑的交互单元。挂靠在 date-picker__header 下会导致样式污染、测试爆炸、动效耦合。
立即学习“前端免费学习笔记(深入)”;
- 正确结构:
<div class="date-picker__panel"> <div class="year-selector"></div> <div class="month-selector"></div> <div class="calendar-grid"></div> </div> - 它们的内部命名各自遵循 BEM:
year-selector__button、month-selector__list、month-selector__option--current - 如果二级月份控件需要不同 z-index 或过渡时长,用
month-selector--compact这类 Modifier,而不是date-picker__month-selector
dropdown 实例必须嵌在 date-picker__panel 里
日期选择器的弹层本质是 dropdown 行为,但很多人误以为它和 date-picker 是父子关系,于是写 date-picker__dropdown。其实它应该是一个独立的 dropdown Block,只是被嵌入到 date-picker__panel 中。
-
date-picker只负责触发、绑定表单属性(name、required)、控制宽度与禁用态 -
dropdown负责面板定位、过渡、键盘导航(↑↓←→移动焦点)、Esc关闭 -
dropdown__toggle和dropdown__menu必须保持 DOM 相邻或父子关系,否则:hover + .dropdown__menu会断链——Vue 的<transition></transition>或 React 的 Fragment 很容易破坏这个前提
calendar-grid__day--disabled 的计算逻辑。它可能来自 min/max 属性、工作日规则、后端返回的不可用日期数组,甚至组合条件。这部分必须抽离成纯函数,和 Block 命名解耦——类名只是输出,不是源头。


















