Files
workspace/code/g3soft-libs/docs/content/ui/data/date.md
T
2026-10-09 17:32:14 +08:00

9.0 KiB
Raw Blame History

title, description
title description
DatePicker 日期选择 日期 / 日期时间 / 范围选择与时间滚轮(DatePicker / RangePicker / TimeSelect)

日期选择

本页包含三个组件:G3DatePicker(单选日期 / 日期时间)、G3RangePicker(日期范围)、G3TimeSelect(时 / 分 / 秒滚轮)。

它们的绑定值都是字符串(TimeSelect 除外,它绑定 Date),因此可以直接和后端接口对接,不需要在业务层做序列化。

基础用法

精度与格式

format 同时决定三件事:面板粒度、展示格式、绑定值格式的默认值;valueFormat 只影响绑定值。

写法 面板 绑定值
format="YYYY" 年选择器 2026
format="YYYY-MM" 年月选择器 2026-10
format="YYYY-MM-DD"(默认) 日期网格 2026-10-08
format="YYYY-MM-DD HH:mm" 日期网格 + 时间列 + 确定按钮 2026-10-08 09:30
format="YYYY-MM-DD HH:mm" + value-format="YYYY-MM-DD HH:mm:ss" 同上 2026-10-08 09:30:00

支持的格式 token:YYYY YY MM M MMM MMMM DD D Do dd ddd dddd HH H hh h mm m ss s SSS A a Z ZZ。

禁用日期与清除

disabledDate 接收 Date,返回 true 表示该日不可选(禁用的格子不可聚焦、不可点击、不参与 hover 预览)。timeDefault 只在「没有值时点开面板」时决定时间初值:'start' 当天 00:00、'end' 当天 23:59:59、不传用当前时刻。

手输与键盘微调

输入框可以直接键入,容错规则如下:

输入 结果
2026-10-08 / 2026/10/08 / 2026年10月8日 都能解析(分隔符互认)
2026-10(部分输入) 解析为 2026-10-01
2026-13-45 判定非法:红框 1.5 秒后回填已提交值,不会写入绑定值
空串 视为清空(''),不是错误

键盘:Esc 取消编辑、Enter 提交并关闭、↑ / ↓ 微调光标所在的段(年 / 月 / 日 / 时 / 分)、Alt + ↓ 打开面板并把焦点交给日历。

日期范围

两次点击确定起止;第二次点击的位置比起点更早时会自动交换。只点了一次就关闭面板不会写入值。

时间滚轮

TimeSelect 绑定 Date,fields 决定显示哪几列,hour12 追加 am/pm 列。

API

Props(DatePicker)

名称 类型 默认值 说明
modelValue string | Date | null null 绑定值。字符串按 valueFormat 解析
format string | string[] 'YYYY-MM-DD' 展示格式与面板粒度
valueFormat string | string[] 跟随 format 绑定值格式
clearable boolean true 有值时显示清除按钮
disabled boolean false 禁用态
disabledDate (date: Date) => boolean — 禁用某些日期
timeDefault '' | 'start' | 'end' '' 无值时的默认时间

Props(RangePicker)

名称 类型 默认值 说明
modelValue Array<string | Date | null> | null null [start, end],元素可为空串
format string | string[] 'YYYY-MM-DD' 展示格式与面板粒度
valueFormat string | string[] 跟随 format 绑定值格式
clearable boolean true 显示清除按钮
disabled boolean false 禁用态
disabledDate (date: Date) => boolean — 禁用某些日期

Props(TimeSelect)

名称 类型 默认值 说明
modelValue Date | null null 当前时间;为空时以当前时刻为基准
fields Array<'hour' | 'minute' | 'second'> ['hour','minute','second'] 显示哪几列
hour12 boolean false 12 小时制(小时列 1-12 + 追加 am/pm 列)
lowerMeridiem boolean false 上下午显示小写 am / pm
disabled boolean false 禁用态

Events

组件 事件 参数 说明
DatePicker update:modelValue / change (value: string) 提交后的字符串值;清空为 ''
RangePicker update:modelValue / change (value: string[]) [start, end];清空为 ['', '']
TimeSelect update:modelValue (value: Date) 时间变化,恒为 Date

类型定义

export type DateValue = string | Date | null | undefined
export type DateTimeDefault = '' | 'start' | 'end'
export type TimeField = 'hour' | 'minute' | 'second'

export interface DatePickerProps {
  modelValue?: DateValue
  format?: string | string[]
  valueFormat?: string | string[]
  clearable?: boolean
  disabled?: boolean
  disabledDate?: (date: Date) => boolean
  timeDefault?: DateTimeDefault
}

export interface RangePickerProps {
  modelValue?: Array<string | Date | null> | null
  format?: string | string[]
  valueFormat?: string | string[]
  clearable?: boolean
  disabled?: boolean
  disabledDate?: (date: Date) => boolean
}

export interface TimeSelectProps {
  modelValue?: Date | null
  fields?: TimeField[]
  hour12?: boolean
  lowerMeridiem?: boolean
  disabled?: boolean
}

工具函数

日期运算不依赖 dayjs,@g3soft/ui 导出了一组纯函数,业务可复用:

函数 签名 说明
formatDate (value, format?) => string 按 token 格式化
parseDate (value, format?) => Date | null 严格匹配 → 规范化文本 → 原生解析三级回退
parseDateInput (text, format) => { date, isEmpty, isValid } 手输解析,区分「空」与「非法」
analyzeDateFormat (format) => DateFormatConfig 解析出 hasYear / hasTime / timeFields / hour12 …
normalizeDateValue / normalizeDateForFormat (value, format) => Date | null 值归一与按精度归零
getMonthMatrix / getMonthRows (year, month) => Date[] / Date[][] 42 格月历(周日起始)
startOfDay / endOfDay / isSameDay / isSameMonth / isToday — 日粒度判断
compareDay / compareDate / isInRange / addMonth / combineDateTime — 比较与合成
listDateSegments / resolveDateSegment / stepDateSegment — 手输光标分段与微调

样式变量

面板形态(尺寸与颜色)都可通过同名 CSS 变量覆盖:

变量 默认值 说明
--g3-calendar-main-width 252px 日历主体定宽(7 列 × 36px)。定宽而非被输入框拉伸
--g3-calendar-height 292px 日历区与时间列共用的高度(表头 40 + 星期行 36 + 6 行 × 36)
--g3-calendar-cell-size 24px 单元格内块尺寸:选中 / 今日方块的边长、范围背景带的厚度
--g3-time-col-width 56px 时间列每列宽度(时 / 分 / 秒各一列)
--g3-time-item-height 28px 时间列单项高度
--g3-time-select-height 196px G3TimeSelect 独立使用时的整块高度(在面板内改由日历区高度决定)

实现说明

  • 零第三方依赖:fms 版依赖 dayjs + 两个插件,这里用 date/date-utils.ts 自研实现(格式化 token、严格解析、段定位、微调步进),保持组件库只依赖 vue;
  • 值的内部表示:内部一律用 Date 运算,对外一律字符串。展示用 format、绑定值用 valueFormat,两者可以不同(展示到分钟、绑定到秒);
  • 不污染绑定值:手输过程只改本地文本,失焦 / 回车才提交;非法输入进错误态并回填旧值——表单里绝不允许出现「半天没法提交但看不出哪里错」的状态;
  • 面板是草稿值:有时间精度时,点选只改草稿、点「确定」才提交;没有时间精度时点选即提交并关闭。关闭面板会丢弃草稿;
  • 定位复用 Popover(trigger="manual"、placement="bottom-start"、unwrapped):弹窗内打开日期面板、滚动跟随、Esc 关闭这些行为与 Select 一致;但面板不跟随触发框宽度(Select 才用 followTriggerWidth),日历定宽 252px,输入框再宽也不会把日期格子撑散;
  • 单元格形态对齐 antd:内块是 24px 的圆角方块(不是圆形);「今日」用 1px 主色描边(不改文字色,选中时描边与填充叠加);范围高亮是厚度 24px 的整条背景带(起止两端各染半段、端点内块只在朝外一侧倒角),所以跨格的范围能连成一条连续色带;
  • 键盘可达性:日历是 role="grid",格子为 role="gridcell",只有当前格子 tabindex=0(roving tabindex),← → ↑ ↓ Home End PageUp PageDown 都能操作,且会跳过禁用日期;底部时间列是 role="listbox",↑ ↓ 步进 1、PageUp/PageDown 步进 5。