跳转到内容

TimeField 时间字段 ​

按时、分、秒逐段输入时间,适合已经知道目标时间、无需打开选择面板的场景。

用法 ​

逐段输入并实时获得标准时间值;有值时可以一键清空

09:30
当前值:09:30

组件结构 ​

加粗的是必需部件。

data-scope="time-field":root · label · control · segment-group · segment · clear-trigger · hidden-input

示例 ​

12 小时制 ​

hour-cycle=12 多出一个上午/下午段,值本身仍是 24 小时的串

01:45 PM
当前值:13:45

精度到秒 ​

granularity=second 使秒段显示并参与值,空段按上下键从该段边界起步

--:--:--
当前值:(未填齐)

禁用与越界 ​

禁用整组退出 Tab 序列;越界只做标注,08:00 原样保留不被改写

13:45
08:00

变体 ​

variant 只改变分段框的底色与描边用法,分段结构与键盘行为都不变

09:30
09:30
09:30

颜色 ​

tone 决定使用哪族颜色,与 variant 正交;这里固定 subtle 形态,只查看语气这一轴

09:30
09:30
09:30
09:30
09:30
09:30

尺寸 ​

不传 size 即默认档;行高、内边距与字号一起换档,标题也随之变化

09:30
09:30
09:30

外部写值与清空 ​

值由宿主持有,按钮直接写值;框内自带清空按钮,有值时才显示,点击后焦点回到第一段

--:--
未填齐

可选值白名单 ​

值交给宿主持有,写回的时间被吸附到清单中的一格,上下键与数字键因此都落在清单上

08:00
只收 08:00 / 12:00 / 18:00,当前值:08:00

设计指引 ​

何时使用 ​

  • 用户知道确切时间,键入比浏览列表更快。
  • 需要 12 小时制并带上下午段位。

何时不用 ​

特性 ​

  • hourCycle 切换 12 / 24 小时制,12 小时制时自动增加上下午段位。
  • granularity 决定精确到分还是到秒。
  • min / max 越界时只标注不改写。
  • 标准组合包含标签、输入框、时间段和隐藏表单输入;聚焦只强调正在编辑的时间段。
  • 框内自带清空按钮(clear-trigger):有值时才显示,点击后焦点回到第一段。
  • 聚焦环、边框和当前段位使用同一段短过渡,焦点进入与离开不会瞬时跳变。

组合 ​

最佳实践 ​

  • 明确时区归属:组件处理的是本地时间,时区换算由宿主负责。
  • 给参与表单提交的字段设置 name,并渲染隐藏输入部件。
  • 12 小时制下上下午段位不能省略,否则用户输入的时间有歧义。

反模式 ​

  • 用文本输入接收时间再解析。

API 参考 ​

产物 ​

层值
自定义元素<xh-time-field>
Vue 组件XhTimeFieldClearTrigger XhTimeFieldControl XhTimeFieldHiddenInput XhTimeFieldLabel XhTimeFieldRoot XhTimeFieldSegment XhTimeFieldSegmentGroup
组合式函数useTimeField
状态机timeFieldMachine
皮肤@xihan-ui/styles/time-field.css

Props ​

属性类型必填说明
valuestring受控值,ISO 时间串。提供即受控:cell 直读 prop,写入只发 onValueChange 不落内部值。
defaultValuestring
minstring下界(含)。只用于标注越界,不改写用户填写的内容。
maxstring上界(含)。同上。
localestringBCP 47 语言标记。决定上午 / 下午的文字,以及未显式提供 hourCycle 时的小时制。
hourCycleTimeHourCycle小时制。未提供时按 locale 推断,locale 也没有时使用 24。
granularityTimeGranularity值精确到哪一段,默认 minute。
disabledboolean禁用:段整体退出 Tab 序列、键盘一概不响应,隐藏输入不参与提交。
readOnlyboolean只读:仍可聚焦、可用左右键在段间移动,但不可修改值。
invalidboolean校验失败标注。
requiredboolean必填标注(写入每段的 aria-required)。
namestring表单字段名;提供后隐藏输入才带 name,值随表单一并提交。
placeholderstring空段的占位字符(单字符),按段宽重复,默认 '-'。
variantControlVariant形态:outline / subtle / ghost,决定底色与描边的绘制方式。默认 outline。
toneTone语气:brand / neutral / success / warning / danger / info,决定聚焦与强调使用哪族颜色。
sizeSize尺寸:sm / md / lg。
translationsPartial<TimeFieldTranslations>段位读屏名的覆盖;未提供时使用内置英文语义名。
onValueChange(details: TimeFieldValueChangeDetails) => void

事件 ​

自定义元素将载荷放在 detail;Vue 使用同名 emit。

事件载荷说明
value-changeTimeFieldValueChangeDetails值变化;detail 为 { value: string }

插槽 ​

仅列出带载荷的插槽。

Vue 组件插槽载荷说明
XhTimeFieldRootdefaultTimeFieldRootSlotProps

React 适配器 props ​

只列各组件自己声明的那些:继承自 ComponentPropsWithRef 的 DOM 属性不在其中,根组件上与上面 Props 表同名的也不重复列。Vue 的对应物是上面的插槽表。

React 组件属性类型必填说明
XhTimeFieldRootchildrenSlotChildren<TimeFieldRootSlotProps>
XhTimeFieldSegmentsegmentTimeSegmentType是段的身份由作者声明。

状态 ​

以下名称仅用于内部状态机。

状态:idle

事件:VALUE.SET · VALUE.CLEAR · SEGMENT.STEP · SEGMENT.DIGIT · SEGMENT.CLEAR · SEGMENT.PERIOD · SEGMENT.FOCUS · SEGMENT.BLUR · FORM.RESET · PRESS.START · PRESS.END

判据:canEdit · canPress

connect API ​

getXxxProps() 返回对应部件的宿主属性。

成员类型说明
valuestringISO 时间串;任一必填段为空时为空串。
emptyboolean值为空串(尚未填全)。作者据此启用提交按钮或显示提示。
outOfRangeboolean已填全但落在 min / max 之外。只是标注,不改写值。
disabledboolean
readOnlyboolean
invalidboolean
canClearboolean有值且可编辑(既不 disabled 也不 readOnly);清空按钮据此显隐。
hourCycleTimeHourCycle实际生效的小时制(prop 未提供时由 locale 推断的值)。
granularityTimeGranularity
segmentsTimeSegmentType[]当前参与显示的段,文档序。未列入的段由 connect 写上 hidden 收起。
focusedSegmentTimeSegmentType | null焦点所在段;焦点在组外时为 null。
getSegmentText(props: TimeFieldSegmentProps) => string某一段应显示的文字(空段是占位串)。各适配器都用它填充文本,保证同构。
setValue(next: string) => void
clear() => void
getRootProps() => T['element']
getLabelProps() => T['label']
getControlProps() => T['element']
getSegmentGroupProps() => T['element']段位与分隔符的外壳:占满盒内剩余宽度,把清空按钮推到框内末端。
getSegmentProps(props: TimeFieldSegmentProps) => T['element']
getClearTriggerProps() => T['button']清空按钮:有值才显示,不占 Tab 位,点击后焦点回到第一段。
getHiddenInputProps() => T['input']表单出口:一份 type=hidden 的原生输入,随表单提交 ISO 串。

无障碍 ​

键盘 ​

规格出处:W3C APG

按键生效条件行为
ArrowUpfocus in a segment, not disabled/readOnly本段加一格,到头回绕;空段落到该段下界
ArrowDownfocus in a segment, not disabled/readOnly本段减一格,到头回绕;空段落到该段上界
ArrowRightfocus in a segment, not disabled焦点移到下一段;已在末段则不动,不回绕
ArrowLeftfocus in a segment, not disabled焦点移到上一段;已在首段则不动,不回绕
Homefocus in a segment, not disabled焦点移到首段
Endfocus in a segment, not disabled焦点移到末段
0-9focus in a 数字段, not disabled/readOnly把数字并进本段;本段再吃不下第二位时自动跳到下一段
Backspace / Deletefocus in a segment, not disabled/readOnly清掉本段;小时被清时上下午段仍保留原来的上午/下午
Enter / Spaceheld in clear-trigger, 有值, not disabled/readOnly按住期间清空按钮投影 data-pressed,与指针 :active 同一副按压面;抬起或失焦撤下,值清空后按钮藏起一并撤下。清空按钮不占 Tab 位,键盘这一路只在焦点落到它身上时有面
a / pfocus in 上下午段, 12 小时制, not disabled/readOnlya 取上午、p 取下午(不区分大小写)

ARIA ​

以下属性由 connect 生成。

部件属性值
controlaria-disabled'true' | 'false'
controlaria-invalid'true' | 'false'
controlaria-labelledbylabel 部件的 id
controlrole'group'
segmentaria-disabled'true' | 'false'
segmentaria-invalid'true' | 'false'
segmentaria-labelprop('translations')?.[segment]
segmentaria-readonly'true' | 'false'
segmentaria-required'true' | 'false'
segmentaria-valuemaxrange.max
segmentaria-valueminrange.min
segmentaria-valuenowsegmentNumber(draft, segment, hourCycle)
segmentaria-valuetexttimeSegmentText(draft, segment, { hourCycle, locale, …
segmentrole'spinbutton'
clear-triggeraria-labelprops.translations.clearTrigger

样式参考 ​

皮肤 ​

@xihan-ui/styles/time-field.css 使用 [data-scope="time-field"][data-part="root"] 部件选择器,位于 xihan.components 层。覆盖样式使用 xihan.overrides。

forced-colors: active 下另有一套规则:颜色交给系统,边框与状态标记改用系统色关键字。

数据属性 ​

由 connect 生成;条件不成立时不输出无值属性。

部件属性值
rootdata-disabled''(条件成立时才出现)
rootdata-empty''(条件成立时才出现)
rootdata-invalid''(条件成立时才出现)
rootdata-out-of-range''(条件成立时才出现)
rootdata-readonly''(条件成立时才出现)
rootdata-sizeprops.size
rootdata-toneprops.tone
rootdata-variantprops.variant
labeldata-disabled''(条件成立时才出现)
controldata-disabled''(条件成立时才出现)
controldata-empty''(条件成立时才出现)
controldata-invalid''(条件成立时才出现)
controldata-readonly''(条件成立时才出现)
controldata-variantprops.variant
controldata-xh-field-chrome''
controldata-xh-field-sizeprops.size
segment-groupdata-disabled''(条件成立时才出现)
segment-groupdata-invalid''(条件成立时才出现)
segment-groupdata-readonly''(条件成立时才出现)
segmentdata-disabled''(条件成立时才出现)
segmentdata-focus''(条件成立时才出现)
segmentdata-invalid''(条件成立时才出现)
segmentdata-placeholder''(条件成立时才出现)
segmentdata-readonly''(条件成立时才出现)
clear-triggerdata-pressed''(条件成立时才出现)
clear-triggerdata-xh-action-control''
clear-triggerdata-xh-action-display'has-value'
clear-triggerdata-xh-action-has-value''(条件成立时才出现)
clear-triggerdata-xh-action-profile'field-inset'
clear-triggerdata-xh-action-sizeprops.size
clear-triggerdata-xh-action-variant'ghost'

CSS 变量 ​

本组件公开覆盖槽由独立皮肤的实际消费位生成;默认来源、作用部件和状态均与 CSS 同源。

变量部件CSS 属性状态默认来源说明
--xh-time-field-action-bgclear-trigger--xh-ink-surface
background-color
default
xh-ink-surface
--xh-_action-variant-bg-resttime-field 的 clear-trigger 部件 --xh-ink-surface、background-color 覆盖槽。
--xh-time-field-action-bg-activeclear-triggerbackground-colordisabled
is(:active, [data-pressed])
loading
not([data-disabled])
not([data-loading])
pressed
--xh-_action-variant-bg-pressedtime-field 的 clear-trigger 部件 background-color 覆盖槽。
--xh-time-field-action-bg-hoverclear-triggerbackground-colordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-_action-variant-bg-hovertime-field 的 clear-trigger 部件 background-color 覆盖槽。
--xh-time-field-action-fgclear-triggercolordefault--xh-fg-mutedtime-field 的 clear-trigger 部件 color 覆盖槽。
--xh-time-field-action-fg-hoverclear-triggercolordisabled
hover
loading
not([data-disabled])
not([data-loading])
--xh-fg-defaulttime-field 的 clear-trigger 部件 color 覆盖槽。
--xh-time-field-action-font-sizeclear-triggerfont-sizedefault--xh-text-secondary-sizetime-field 的 clear-trigger 部件 font-size 覆盖槽。
--xh-time-field-action-radiusclear-triggerborder-radiusdefault--xh-shape-insettime-field 的 clear-trigger 部件 border-radius 覆盖槽。
--xh-time-field-action-sizeclear-triggerblock-size
inline-size
min-inline-size
default
xh-action-profile=field-inset
--xh-_action-profile-visual-sizetime-field 的 clear-trigger 部件 block-size、inline-size、min-inline-size 覆盖槽。
--xh-time-field-control-bgcontrolbackground-colorxh-field-chrome--xh-_field-variant-bg-resttime-field 的 control 部件 background-color 覆盖槽。
--xh-time-field-control-bg-disabledcontrolbackground-colordisabled
xh-field-chrome
--xh-_field-variant-bg-disabledtime-field 的 control 部件 background-color 覆盖槽。
--xh-time-field-control-bg-hovercontrolbackground-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-bg-hovertime-field 的 control 部件 background-color 覆盖槽。
--xh-time-field-control-bg-readonlycontrolbackground-colorreadonly
xh-field-chrome
--xh-_field-variant-bg-read-onlytime-field 的 control 部件 background-color 覆盖槽。
--xh-time-field-control-bordercontrolborderxh-field-chrome--xh-_field-variant-border-resttime-field 的 control 部件 border 覆盖槽。
--xh-time-field-control-border-focuscontrolborder-colordisabled
focus-within
not([data-disabled])
xh-field-chrome
--xh-_field-variant-border-focustime-field 的 control 部件 border-color 覆盖槽。
--xh-time-field-control-border-hovercontrolborder-colordisabled
hover
invalid
loading
not([data-disabled])
not([data-invalid])
not([data-loading])
not([data-readonly])
readonly
xh-field-chrome
--xh-_field-variant-border-hovertime-field 的 control 部件 border-color 覆盖槽。
--xh-time-field-control-border-invalidcontrolborder-colorinvalid
xh-field-chrome
--xh-_field-variant-border-invalidtime-field 的 control 部件 border-color 覆盖槽。
--xh-time-field-control-fgcontrolcolorxh-field-chrome--xh-fg-defaulttime-field 的 control 部件 color 覆盖槽。
--xh-time-field-control-gapcontrolgapxh-field-chrome--xh-_time-field-gaptime-field 的 control 部件 gap 覆盖槽。
--xh-time-field-control-hcontrolblock-size
min-block-size
has([data-xh-field-input][data-xh-field-layout='multi-tag'])
has([data-xh-field-input][data-xh-field-layout='single-line'])
has([data-xh-field-input][data-xh-field-layout='textarea'])
xh-field-chrome
xh-field-input
xh-field-layout=multi-tag
xh-field-layout=single-line
xh-field-layout=textarea
--xh-_time-field-control-htime-field 的 control 部件 block-size、min-block-size 覆盖槽。
--xh-time-field-control-min-wcontrol
root
min-inline-sizedefault
xh-field-chrome
--xh-control-min-wtime-field 的 control、root 部件 min-inline-size 覆盖槽。
--xh-time-field-control-pxcontrolpadding-inlinexh-field-chrome--xh-_time-field-control-pxtime-field 的 control 部件 padding-inline 覆盖槽。
--xh-time-field-control-radiuscontrolborder-radiusxh-field-chrome--xh-shape-controltime-field 的 control 部件 border-radius 覆盖槽。
--xh-time-field-control-shadowcontrolbox-shadowxh-field-chromenonetime-field 的 control 部件 box-shadow 覆盖槽。
--xh-time-field-control-wrootinline-size
min-inline-size
default--xh-control-wtime-field 的 root 部件 inline-size、min-inline-size 覆盖槽。
--xh-time-field-font-sizecontrolfont-sizedefault--xh-_time-field-font-sizetime-field 的 control 部件 font-size 覆盖槽。
--xh-time-field-gaprootgapdefault--xh-space-1time-field 的 root 部件 gap 覆盖槽。
--xh-time-field-icon-sizecontrol
root
--xh-icon-sizedefault
size=lg
size=sm
xh-field-chrome
--xh-_field-size-glyph-size
--xh-glyph-size-lg
--xh-glyph-size-md
--xh-glyph-size-sm
time-field 的 control、root 部件 --xh-icon-size 覆盖槽。
--xh-time-field-label-fglabelcolordefault--xh-fg-defaulttime-field 的 label 部件 color 覆盖槽。
--xh-time-field-label-fg-disabledlabelcolordisabled--xh-fg-subtletime-field 的 label 部件 color 覆盖槽。
--xh-time-field-label-font-sizelabelfont-sizedefault--xh-text-label-sizetime-field 的 label 部件 font-size 覆盖槽。
--xh-time-field-label-font-weightlabelfont-weightdefault--xh-text-label-weighttime-field 的 label 部件 font-weight 覆盖槽。
--xh-time-field-literal-fgsegment-groupcolornot([data-scope])--xh-fg-subtletime-field 的 segment-group 部件 color 覆盖槽。
--xh-time-field-placeholder-fgsegmentcolorplaceholder--xh-fg-subtletime-field 的 segment 部件 color 覆盖槽。
--xh-time-field-segment-bg-focussegmentbackgrounddisabled
focus
focus-visible
not([data-disabled])
--xh-_time-field-segment-bgtime-field 的 segment 部件 background 覆盖槽。
--xh-time-field-segment-bg-hoversegmentbackgrounddisabled
focus
hover
not([data-focus], [data-disabled])
--xh-bg-subtletime-field 的 segment 部件 background 覆盖槽。
--xh-time-field-segment-bg-invalid-focussegmentbackgroundfocus
invalid
is([data-focus], :focus-visible)
--xh-bg-subtletime-field 的 segment 部件 background 覆盖槽。
--xh-time-field-segment-fg-focussegmentcolordisabled
focus
focus-visible
not([data-disabled])
placeholder
--xh-_time-field-segment-fgtime-field 的 segment 部件 color 覆盖槽。
--xh-time-field-segment-fg-invalidsegmentcolorinvalid--xh-fg-dangertime-field 的 segment 部件 color 覆盖槽。
--xh-time-field-segment-fg-invalid-focussegmentcolorfocus
invalid
is([data-focus], :focus-visible)
--xh-fg-dangertime-field 的 segment 部件 color 覆盖槽。
--xh-time-field-segment-pxsegmentpadding-inlinedefault--xh-space-0_5time-field 的 segment 部件 padding-inline 覆盖槽。
--xh-time-field-segment-pysegmentpadding-blockdefault--xh-space-0time-field 的 segment 部件 padding-block 覆盖槽。
--xh-time-field-segment-radiussegmentborder-radiusdefault--xh-shape-insettime-field 的 segment 部件 border-radius 覆盖槽。

动效 ​

动效角色:按压 · 状态(见动效规范)。

background-color · color 走 transition 过渡。时长与缓动读动效令牌,改令牌即改全局节奏。

系统开启减弱动效时由令牌层统一收敛,皮肤不另作判断。

RTL ​

皮肤用逻辑属性排布(inline-start 一族),dir="rtl" 下自动镜像。

Released under The MIT License