日期选择器应拆分为 date-picker、date-picker__trigger、date-picker__panel 和独立 Block calendar-grid 四个部分,分别承担容器、触发、弹层和日历本体职责,确保职责分离与复用性。

日期选择器该拆成哪几个 Block?
不能把整个日历面板硬套一个 date-picker 块就完事。它天然包含三类职责分离的子系统:触发入口、弹层容器、日历网格,必须拆成独立 Block,否则 JS 控制逻辑和样式都会互相污染。
-
date-picker:仅负责外层容器定位、宽度、禁用态、表单集成(如绑定 name / required) -
date-picker__trigger:输入框 + 图标区域,响应点击/键盘事件,不渲染日历 -
date-picker__panel:绝对定位弹层,含年份切换、月份标题、周头、日期格子等完整日历 DOM -
calendar-grid(独立 Block):日历本体,可复用于其他场景(如行程视图),自带calendar-grid__day、calendar-grid__week-header
错误做法是写 date-picker__calendar__day —— BEM 不允许 element 嵌套 element,且 calendar-grid 本身有复用需求,强行挂靠会锁死它的使用边界。
日期状态该挂在哪一层?
“今天”“已选中”“不可选”“当前月”这些不是视觉修饰,而是数据驱动的状态,必须由 JS 显式控制类名,且归属层级要严格对应语义。
-
date-picker__trigger--has-value:表示输入框已有值(影响占位符、边框色) -
calendar-grid__day--today:仅标记语义上的“今日”,不带交互逻辑 -
calendar-grid__day--selected:由 JS 切换,且支持多选时可叠加(如calendar-grid__day--selected calendar-grid__day--range-start) -
calendar-grid__day--disabled:基于 min/max 或业务规则禁用,CSS 只管透明度和 pointer-events
别用 :disabled 或 :checked 模拟这些状态 —— 日期选择器几乎不用原生 <input type="date">,DOM 是自定义的,伪类不可靠,无障碍属性(aria-current、aria-disabled)也得靠 JS 同步更新。
如何处理年份/月份切换控件的命名?
年份选择器(如「2024」按钮)和月份选择器(如「六月」下拉)不是 date-picker__header 的子元素,它们是独立交互单元,有自己的状态和焦点管理。
- 用
year-selector和month-selector作为独立 Block,而非date-picker__year-selector - 它们内部元素命名遵循各自 BEM 规则:
year-selector__button、month-selector__list、month-selector__option--current - 在
date-picker__panel中直接嵌入实例:<div class="year-selector"></div> <div class="month-selector"></div>
这样做的好处是:年份控件可单独测试、可被复用于时间轴组件;月份下拉的键盘导航逻辑(↑↓Enter)不依赖 date-picker 的 JS 上下文;构建工具打包时也能按需加载。
BEM 类名在日期组件里最容易踩的坑
日期选择器对类名拼写和构建链路极其敏感,稍不注意就会样式丢失或状态错乱。
- 构建工具(如 Vite + cssnano)默认开启
mergeLonghand,可能把date-picker--range date-picker--disabled压缩成date-picker--range,必须在 PostCSS 配置中显式禁用 - JS 动态添加类名时,别手拼字符串:
el.className += ' date-picker__trigger--focused'—— 容易重复添加或漏空格,改用el.classList.add('date-picker__trigger--focused') -
calendar-grid__day上禁止声明 CSS 变量(如--day-bg),变量必须挂在calendar-grid块级上,子元素继承使用 - 响应式隐藏某列(如周日)不要用
display: none直接作用于calendar-grid__day--sunday,而应加修饰符calendar-grid--hide-sunday,保持样式作用域清晰
最常被忽略的是:日期组件内所有可聚焦元素(calendar-grid__day、year-selector__button)必须带 tabindex="0",且 --focused 修饰符只由 focus / blur 事件控制,不能和 --hovered 混用 —— 键盘用户和鼠标用户的反馈路径必须隔离。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











