SuperAPI AI 工具集

date-picker

前端与建站

查看项目

更新于 10-16 05:30

技能介绍

用途

Date Picker 是一种表单组件,由显示所选日期的文本输入框和日历浮层组成,用户可以通过日历可视化地浏览并选择日期。日历能提供纯文本输入无法给出的上下文,例如周边日期、星期几以及时间相对位置。

与针对已知日期直接键盘输入的 Date Input 不同,Date Picker 适用于用户需要看到日历的场景:预约排期、选择未来配送日期,或从受限的可用日期集合中选择。

适用场景

  • 预约排期:用户需要在上下文中查看可用时段。
  • 配送与发货日期:展示可用配送日与不可用日期。
  • 活动创建:用户选择相对于今天或其他活动的日期。
  • 酒店与旅行预订:结合价格或可用性的上下文日期选择。
  • 报表或筛选日期:为数据筛选选择特定日期。

应避免的场景

  • 已知的历史日期:出生日期或过往记录应使用 Date Input,日历导航较为繁琐。
  • 日期范围:应改用 Date Range 组件。
  • 仅移动端场景:原生 <input type="date"> 会打开平台原生选择器,自定义日历可能多余。
  • 非常久远的日期:在日历中导航 80 年以上不切实际,应使用带年份输入的文本日期输入。

实现流程

  1. 在复制示例前,先确认该模式与问题和约束匹配。
  2. 从 references/pattern.md 中的结构和示例开始,选择最小可行的变体。
  3. 在叠加视觉打磨之前,先应用可访问性、性能和交互防护规则。
  4. 使用测试指南验证键盘、屏幕阅读器、响应式和失败场景下的行为。

可访问性防护规则

键盘交互模式:

按键 操作
Enter / Space 在触发按钮上打开日历;选择聚焦日期
Escape 关闭日历并将焦点返回触发按钮
Arrow Right 焦点移到下一天
Arrow Left 焦点移到上一天
Arrow Down 焦点移到下周同一天
Arrow Up 焦点移到上周同一天
Home 焦点移到当前周的第一天

性能防护规则

  • 日历打开时间:从按钮点击到日历可见 < 100ms
  • 月份导航:渲染新月份网格 < 50ms
  • 日期选择:从点击到输入更新并关闭弹层 < 16ms
  • 内存占用:每个日期选择器实例 < 20KB
  • DOM 大小:单月日历网格 < 50 个节点

常见错误

在输入框获得焦点时打开日历

问题:当文本输入框获得焦点时自动打开日历,会干扰通过表单导航的键盘用户,以及偏好直接输入日期的用户。

修复方式:仅在日历图标按钮被激活时打开日历。

// Bad
dateInput.addEventListener('focus', openCalendar);

// Good
calendarButton.addEventListener('click', toggleCalendar);
calendarButton.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault();
    toggleCalendar();
  }
});

日历网格中没有键盘导航

问题:需要鼠标交互的日历对键盘和屏幕阅读器用户不可访问。

修复方式:实现完整的 ARIA 网格键盘导航模式。

calendarGrid.addEventListener('keydown', (e) => {
  const focused = document.activeElement;
  switch (e.key) {
    case 'ArrowRight': focusDay(getNextDay(focused)); break;
    case 'ArrowLeft':  focusDay(getPrevDay(focused)); break;
    case 'ArrowDown':  focusDay(getNextWeek(focused)); break;
    case 'ArrowUp':    focusDay(getPrevWeek(focused)); break;
    case 'Home':       focusDay(getFirstDayOfWeek(focused)); break;
    case 'End':        focusDay(getLastDayOfWeek(focused)); break;
    case 'PageUp':     navigateToPrevMonth(); break;
    case 'PageDown':   navigateToNextMonth(); break;
    case 'Escape':     closeCalendar(); break;
  }
});

关闭后未返回焦点

问题:日历关闭后(选择日期或按 Escape),焦点消失或跳到页面顶部。

修复方式:始终将焦点返回触发元素。

function closeCalendar() {
  calendarPopup.hidden = true;
  calendarButton.setAttribute('aria-expanded', 'false');
  calendarButton.focus(); // Always return focus
}

相关模式

  • https://uxpatterns.dev/patterns/forms/date-input
  • https://uxpatterns.dev/patterns/forms/date-range
  • https://uxpatterns.dev/patterns/forms/text-field

完整实现细节、示例和测试说明,请参见 references/pattern.md。

模式页面:https://uxpatterns.dev/patterns/forms/date-picker