跳转到内容

时间选择器 time-picker

数据录入组件。三层同源:无头内核给出解剖与状态机,Vue 组件与自定义元素只是它的两层外壳,行为完全一致。

示例

基础用法

段位与列写的是同一个值:段上敲、列里挑,另一边当场跟着改口

--:--
当前值:(空)

分列步长

step=15 只裁浮层里的可选值(分列剩四格),段位上手打的分数不受它限制

09:30
当前值:09:30

12 小时制

时列写的是显示值 01-12,落到哪个真实小时由输入行里的上下午段说了算

09:30上午
值仍是 24 小时的串:09:30

精度到秒

granularity 同时决定输入行显示几段、浮层里排几列

--:--:--
当前值:(空)

禁用 / 只读 / 校验失败

禁用整条退出 Tab 序,只读仍能展开浏览只是改不动值,invalid 只改标注

09:30
09:30
09:30

可选时段

min / max 直接把界外的格从列里裁掉;分列还会随已选的时再裁一遍

--:--
手打进段位的时间不受裁剪限制,越界只被标注:(空)

浮层里的操作按钮

列表下面这排按钮是作者自己的节点,键盘事件在它这一层收口,不再上交给列表

--:--
当前值:(空)

按谓词裁可选值

列里渲染哪几格由作者决定,午休两格整段拿掉;手打进段位的时被吸到下一个可约小时

09:00
当前值:09:00

产物

自定义元素<xh-time-picker>
Vue 组件XhTimePickerClearTrigger XhTimePickerColumn XhTimePickerContent XhTimePickerControl XhTimePickerHiddenInput XhTimePickerInput XhTimePickerItem XhTimePickerLabel XhTimePickerPositioner XhTimePickerRoot XhTimePickerTrigger
组合式函数useTimePicker
状态机timePickerMachine
皮肤@xihan-ui/styles/time-picker.css

解剖

部件名即 data-part 属性值,也是皮肤的选择器。加粗的是必备部件,不渲染它组件不工作(Web Components 适配器会在诊断通道上报 wc.missing-part)。

data-scope="time-picker"root · label · control · input · trigger · clear-trigger · positioner · content · column · item · hidden-input

Props

属性类型必填说明
valuestring受控值,ISO 时间串。给定即受控:cell 直读 prop,写只发 onValueChange 不落内部值。
defaultValuestring
openboolean展开态。给定即受控:内部不再自改,只发 onOpenChange。
defaultOpenboolean
minstring下界(含)。裁掉浮层里落在界外的可选值,并把已填的越界值标注出来(不改写它)。
maxstring上界(含)。同上。
localestringBCP 47 语言标记。决定上午/下午的文字,以及未显式给 hourCycle 时的小时制。
hourCycleTimeHourCycle小时制。不给则按 locale 推断,locale 也没有时用 24。
granularityTimeGranularity值精确到哪一段,默认 minute。它同时决定分段输入显示几段、浮层里排几列。
stepnumber分列的步进(分钟),默认 1。只影响浮层里的可选值,不限制手打进去的分数。
disabledboolean禁用:分段输入整组退出 Tab 序列、触发器用原生 disabled,隐藏输入不参与提交。
readOnlyboolean只读:浮层照常展开、列表照常浏览,但值改不动也清不掉。
invalidboolean校验失败标注。
requiredboolean必填标注(落到每段的 aria-required 上)。
namestring表单字段名;给了隐藏输入才带 name,值随表单一并提交。
placementPlacement
dirDirection文字方向,缺省 ltr。只改写浮层在行内轴上 start 与 end 的落点。
offsetnumber
onValueChange(details: TimePickerValueChangeDetails) => voidvalue 变化意图回调;受控时是唯一出口,非受控随内部写入一并通知。
onOpenChange(details: TimePickerOpenChangeDetails) => voidopen 变化意图回调;受控时是唯一出口,非受控时随内部转移一并通知。

状态机

状态open · closed

事件OPEN · TOGGLE · CLOSE · CONTROLLED.OPEN · CONTROLLED.CLOSE · VALUE.SET · VALUE.CLEAR · SEGMENT.STEP · SEGMENT.DIGIT · SEGMENT.CLEAR · SEGMENT.PERIOD · SEGMENT.FOCUS · SEGMENT.BLUR · OPTION.FOCUS · ITEM.SELECT · FORM.RESET

判据isOpenControlled · canEdit

connect API

useTimePicker 产出的对象。getXxxProps() 铺到对应部件的宿主元素上,其余是可读状态与操作入口。

成员类型说明
openboolean
valuestringISO 时间串;任一必填段为空时是空串。
emptyboolean值为空串(还没填全)。
outOfRangeboolean已填全但落在 min/max 之外。只是标注,不改写值。
disabledboolean
readOnlyboolean
invalidboolean
hourCycleTimeHourCycle实际生效的小时制(prop 没给时由 locale 推出来的那个)。
granularityTimeGranularity
stepnumber实际生效的分列步进。
segmentsTimeSegmentType[]此刻参与显示的段,文档序。未列入的段由 connect 打上 hidden 收起。
focusedSegmentTimeSegmentType | null焦点所在段;焦点在分段输入外时为 null。
columnsTimePickerColumn[]此刻该排哪几列、每列有哪些可选值(已按 step 与 min/max 裁过)。作者据此渲染浮层。
focusedColumnTimePickerColumnUnit | null
focusedItemstring | null
canClearboolean清空按钮此刻可不可按。
getSegmentText(props: TimePickerInputProps) => string某一段该显示的文字(空段是占位串)。两个适配器都拿它填文本,保证同构。
isItemSelected(props: TimePickerItemProps) => boolean
isItemDisabled(props: TimePickerItemProps) => boolean落在 min/max 之外(或整个控件禁用):仍在列表里,但不可选、方向键跳过。
setOpen(next: boolean) => void
setValue(next: string) => void
clear() => void
getRootProps() => T['element']
getLabelProps() => T['label']
getControlProps() => T['element']
getInputProps(props: TimePickerInputProps) => T['element']分段输入:一段一个节点,与 TimeField 的段同构(role=spinbutton + roving tabindex)。
getTriggerProps() => T['button']
getClearTriggerProps() => T['button']
getPositionerProps() => T['element']
getContentProps() => T['element']
getColumnProps(props: TimePickerColumnProps) => T['element']
getItemProps(props: TimePickerItemProps) => T['element']
getHiddenInputProps() => T['input']表单出口:一份 type=hidden 的原生输入,随表单提交 ISO 串。

键盘

规格出处:W3C APG

按键生效条件行为
ArrowDown / ArrowUpfocus in trigger, closed, not disabled展开浮层,焦点落到时列(已选的时仍可选就停在它上面,否则停在首格)
Enter / Spacefocus in trigger, not disabled按钮的默认激活即展开/收起(不额外拦键,否则会一开一关)
ArrowDownopen, focus in 某一列列内下移一格,到尾回绕;被 min/max 裁掉的格自动跳过
ArrowUpopen, focus in 某一列列内上移一格,到头回绕;被 min/max 裁掉的格自动跳过
Homeopen, focus in 某一列焦点移到本列首格
Endopen, focus in 某一列焦点移到本列末格
ArrowRightopen换到下一列并落在该列的锚点上;已在末列则不动,不回绕
ArrowLeftopen换到上一列并落在该列的锚点上;已在首列则不动,不回绕
Enter / Spaceopen, 焦点停在可选的格上, not disabled/readOnly把这一格写进对应的段;浮层不收起(其余列还要接着挑)
Escapeopen收起浮层并把焦点归还触发器,值不变
Tab / Shift+Tabopen收起浮层且不拦按键,焦点按 Tab 序列自然离开,不抢回触发器
ArrowUpfocus in 某一段, not disabled/readOnly本段加一格,到头回绕;空段落到该段下界
ArrowDownfocus in 某一段, not disabled/readOnly本段减一格,到头回绕;空段落到该段上界
ArrowRightfocus in 某一段, not disabled焦点移到下一段;已在末段则不动,不回绕
ArrowLeftfocus in 某一段, not disabled焦点移到上一段;已在首段则不动,不回绕
Homefocus in 某一段, not disabled焦点移到首段
Endfocus in 某一段, not disabled焦点移到末段
0-9focus in 数字段, not disabled/readOnly把数字并进本段;本段再吃不下第二位时自动跳到下一段
Backspace / Deletefocus in 某一段, not disabled/readOnly清掉本段;小时被清时上下午段仍保留原来的上午/下午
a / pfocus in 上下午段, 12 小时制, not disabled/readOnlya 取上午、p 取下午(不区分大小写)

Released under The MIT License