9.0 KiB
9.0 KiB
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。