输入类

时间选择器

用户使用时间选择器可以方便地选择某一符合要求的、格式化的时间点

代码演示

如何引入

<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

基础使用

点击 TimePicker,然后可以在浮层中选择或者输入某一时间。

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<TimePicker />

无限滚动

版本V2.22.0开始,我们将 TimePicker 内的 ScrollItem 的默认模式从 wheel 变更为了 normal, 若想应用回无限滚动的效果,可参考以下示例。

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<TimePicker scrollItemProps={{ mode: 'wheel', cycled: true }} />

受控组件

使用 bind:value 作为受控组件,没有 defaultValue,初始值直接写在绑定的变量上。传 null 是受控的空值,undefined 视为非受控。清除后单选值为 undefined,范围值为空数组。

代码
<script lang="ts">
    import { TimePicker, type TimePickerBaseValueType } from '@fibrae/semi-ui-svelte';

    let value = $state<TimePickerBaseValueType | TimePickerBaseValueType[] | null>(null);
    const onChange = (time: unknown) => console.log(time);
</script>

<TimePicker bind:value {onChange} />

不同的 Format 格式

TimePicker 浮层中的列会随着 format 变化,当略去 format 中的某部分时,浮层中对应的列也会消失。

NOTE: format 遵循 date-fns v4 的 format 格式。 https://date-fns.org/docs/format

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<TimePicker format="HH:mm" value="10:24" />

设置面板头部,底部

禁用时间选择

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<TimePicker disabled value="12:08:23" />

设置步长

可以使用 hourStep, minuteStep, secondStep 按步长展示可选的时分秒。

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<TimePicker minuteStep={15} secondStep={10} />

12 小时制

12 小时制的时间选择器,默认的 format 为 a h:mm:ss,传入的 format 格式必须在 dateFns 日期格式范围之内。

例如默认的 12 小时制格式串为:a h:mm:ss,如果传入 A h:mm:ss 则会导致无法正确格式化。



代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<div>
    <TimePicker use12Hours />
    <br />
    <br />
    <TimePicker format="a h:mm" use12Hours />
</div>

时间范围

传入 type="timeRange" 开启时间范围选择。



代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';
</script>

<div>
    <TimePicker type="timeRange" value={['10:23:15', '12:38:32']} />
    <br />
    <br />
    <TimePicker format="a h:mm" type="timeRange" use12Hours value={['上午 08:11', '下午 11:21']} />
</div>

Range 模式下分别禁用左右面板(disabledTime)

当 type="timeRange" 时,你可以通过 disabledTime(value, panelType) 对左右面板分别应用不同的禁用规则。

  • value:当前已选时间数组,未选的一侧为 undefined(如 [date, undefined]);没有值时为空数组,value、defaultValue 或输入框只含一个时间时长度为 1
  • panelType:'left' | 'right',分别代表开始/结束面板

下面示例实现:选择开始时间后,右侧结束时间面板会禁用早于开始时间的选项。

代码
<script lang="ts">
    import { TimePicker } from '@fibrae/semi-ui-svelte';

    const range = (length: number) => Array.from({ length }, (_, i) => i);

    // The right panel disables everything earlier than the start time picked on the left
    const disabledTime = (value: (Date | undefined)[], panelType: 'left' | 'right') => {
        const start = value[0];
        if (panelType === 'right' && start) {
            const h = start.getHours();
            const m = start.getMinutes();
            return {
                disabledHours: () => range(h),
                disabledMinutes: (hour: number) => (hour === h ? range(m) : []),
            };
        }
        return {};
    };
</script>

<TimePicker {disabledTime} type="timeRange" />

自定义触发器

默认情况下我们使用 Input 组件作为 TimePicker 组件的触发器,通过 trigger snippet 你可以自定义这个触发器。参数为 { value, inputValue, placeholder, disabled, componentProps, onChange },其中 value 未选的一侧为 undefined,onChange 用于更新输入框文本,效果同键入。

代码
<script lang="ts">
    import * as dateFns from 'date-fns';
    import { IconTimePicker } from '@fibrae/semi-icons-svelte/lab';
    import { Tag, TimePicker, type TimePickerBaseValueType } from '@fibrae/semi-ui-svelte';

    const formatToken = 'HH:mm:ss';
    let time = $state<TimePickerBaseValueType | TimePickerBaseValueType[] | null>(new Date(2024, 0, 1, 10, 30, 0));
</script>

<TimePicker bind:value={time} format={formatToken}>
    {#snippet trigger({ placeholder })}
        <Tag color="cyan" shape="circle" size="large" style="padding: 12px; padding-right: 16px; font-size: 14px" type="light">
            {#snippet prefixIcon()}
                <IconTimePicker />
            {/snippet}
            {time instanceof Date ? dateFns.format(time, formatToken) : placeholder}
        </Tag>
    {/snippet}
</TimePicker>

时区设置

Semi 所有关于时区的配置都收敛在 ConfigProvider 中,详细使用可以参考 ConfigProvider

Select Time Zone:


TimePicker:
代码
<script lang="ts">
    import { ConfigProvider, Select, TimePicker } from '@fibrae/semi-ui-svelte';

    let timeZone = $state('GMT+08:00');
    const defaultTimestamp = 1581599305265;
    const gmtList: string[] = [];
    for (let hourOffset = -11; hourOffset <= 14; hourOffset++) {
        const prefix = hourOffset >= 0 ? '+' : '-';
        gmtList.push(`GMT${prefix}${String(Math.abs(hourOffset)).padStart(2, '0')}:00`);
    }
    const optionList = gmtList.map((gmt) => ({ value: gmt, label: gmt }));

    const onChange = (date: unknown, dateString: string | string[]) => console.log('DatePicker changed: ', date, dateString);
</script>

<ConfigProvider {timeZone}>
    <div style="width: 300px">
        <h5 style="margin: 10px">Select Time Zone:</h5>
        <Select aria-label="时区" onSelect={(value) => (timeZone = String(value))} {optionList} placeholder="请选择时区" showClear style="width: 300px" value={timeZone} />
        <br />
        <br />
        <h5 style="margin: 10px">TimePicker:</h5>
        <TimePicker {onChange} value={defaultTimestamp} />
    </div>
</ConfigProvider>

API 参考

Props

属性说明类型默认值
autoAdjustOverflow浮层被遮挡时是否自动调整方向。booleantrue
autofocus挂载时让输入框获得焦点,同时打开面板。booleanfalse
borderless无边框模式。booleanfalse
clearIcon自定义清除图标,showClear 为 true 时有效。Snippet-
disabled禁用全部操作。boolean-
disabledHours返回禁止选择的小时。Type() => number[]-
disabledMinutes按所选小时返回禁止选择的分钟。Type(selectedHour: number) => number[]-
disabledSeconds按所选小时和分钟返回禁止选择的秒。Type(selectedHour: number, selectedMinute: number) => number[]-
disabledTime仅范围模式生效:按当前值与面板位置返回左右面板各自的禁用规则。value 中未选的一侧为 undefined;返回的 disabledHours、disabledMinutes、disabledSeconds 覆盖对应的同名属性,未返回的回退到同名属性。Type(value: (Date | undefined)[], panelType: PanelType) => DisabledTimeFns-
focusOnOpen挂载后让输入框获得焦点并选中内容,同时打开面板。booleanfalse
format展示的时间格式,遵循 date-fns 的 format;use12Hours 时默认为 a h:mm:ss,否则为 HH:mm:ss。string-
hideDisabledOptions隐藏禁止选择的选项。booleanfalse
hourStep小时选项的间隔,必须是正整数。number-
inputReadOnly输入框只读,避免在移动设备上打开虚拟键盘。booleanfalse
inputStyle输入框根元素的样式。string-
insetLabel输入框的内嵌标签。Snippet-
insetLabelIdinsetLabel 的 id,用于 aria-labelledby 关联。string-
minuteStep分钟选项的间隔,必须是正整数。number-
motion是否展示弹出层动画。booleantrue
onBlur点击外部关闭面板时触发,参数为该次 mousedown 的原生事件;离开输入框不触发。Type(event: MouseEvent) => void-
onChange时间变化时触发,参数为 (Date 值, 格式化字符串),范围模式下两者都是数组;清除后单选为 undefined,范围为空数组,范围中未选的一侧为 undefined。Type(value: Date | (Date | undefined)[] | undefined, str: string | string[]) => void-
onEnterPress输入框上按下 Enter 的回调。Type(event: KeyboardEvent) => void-
onFocus输入框根元素获得焦点时触发;焦点在输入框与清除按钮之间移动不触发。Type(event: FocusEvent) => void-
onKeyDown输入框上的 keydown 回调。Type(event: KeyboardEvent) => void-
onKeyUp输入框上的 keyup 回调。Type(event: KeyboardEvent) => void-
onOpenChange面板打开或关闭时触发。Type(open: boolean) => void-
open面板是否打开,配合 bind:open 使用;undefined 视为非受控。boolean-
panel仅范围模式:同时作为第 index 个面板的头部和底部,有内容时优先于 panelHeader 与 panelFooter。TypeSnippet<[TimePickerPanelSnippetProps]>-
panelFooter面板底部内容的 snippet,参数 index 为面板序号。TypeSnippet<[TimePickerPanelSnippetProps]>-
panelHeader面板头部内容的 snippet,参数 index 为面板序号(单选为 0,范围为 0 或 1)。范围模式下未提供时显示语言包的「开始时间」「结束时间」。TypeSnippet<[TimePickerPanelSnippetProps]>-
placeholder没有值时显示的提示,默认按 type 取语言包文案。string-
popupClassName弹出层的类名。ClassValue-
popupStyle弹出层的样式,字符串。string-
position浮层位置,type 为 timeRange 时默认为 bottom,为 time 时默认为 bottomLeft。Position-
prefix输入框的前缀内容。Snippet-
preventScroll指示浏览器是否应滚动文档以显示新聚焦的元素,作用于组件内的 focus 方法。boolean-
rangeSeparator时间范围的分隔符。string" ~ "
scrollItemProps传给各列的属性,只支持 cycled、mode、motion、transform,含义同 ScrollList 的 ScrollItem。TimePickerScrollItemProps-
secondStep秒选项的间隔,必须是正整数。number-
showClear是否展示清除按钮。booleantrue
size输入框的大小。InputSize-
stopPropagation是否阻止弹出层上的点击事件冒泡。booleantrue
timeZone时区,未设置时依次取 ConfigProvider 的 timeZone、全局默认值。string | number-
trigger自定义触发器的 snippet,替代默认的输入框,点击其中任意位置打开面板。参数含 value(未选的一侧为 undefined)、inputValue、placeholder、disabled、componentProps 与 onChange(更新输入框文本,效果同键入)。TypeSnippet<[TimePickerTriggerRenderProps]>-
type选择类型,time 为单个时间,timeRange 为时间范围。TimePickerType"time"
use12Hours使用 12 小时制。booleanfalse
validateStatus校验状态。ValidateStatus-
value当前时间,配合 bind:value 使用;type 为 timeRange 时为数组。传 null 是受控的空值,undefined 视为非受控。TimePickerBaseValueType | TimePickerBaseValueType[] | null-

Methods

方法说明类型
blur移除输入框的焦点;自定义触发器时无效。Type() => void
focus使输入框获得焦点,同时打开面板;自定义触发器时无效。Type() => void

未声明的属性中,class、style 落在根元素上,其余(id、title、aria-*、data-*、原生事件等)落在内部输入框上;使用 trigger 自定义触发器时,这些属性不落在任何元素上,可通过 componentProps 取用。

通过组件实例调用 focus()、blur(),使用自定义触发器时无效。

Accessibility

ARIA

  • 输入框的 role 为 combobox,带 aria-haspopup="dialog"、随面板开关变化的 aria-expanded,aria-controls 指向面板
  • 时、分、秒与上午/下午列是 role 为 listbox 的列表,名称分别为「小时」「分钟」「秒」「上午或下午」

键盘和焦点

  • 输入框获得焦点时打开面板;面板打开后按 下箭头,焦点移入第一列
  • 每列是一个 Tab 停靠点,上箭头、下箭头、Home、End 或输入字符选择该列的值
  • 按 Esc 关闭面板;焦点在面板内时回到输入框

文案规范

  • 时间选择器至少包括时和分,如:11:30,它在本地化过程中,可以适应为12小时制或者24小时制
  • 当选择12小时制,需要和AM/PM一起搭配使用

设计变量

下表是组件内部的 Sass 变量,不能覆写。定制样式请覆写 --semi-* CSS 变量(见 Design Token 页),或写不分层的 CSS 规则。
Sass 变量值用法
$color-timePicker_range_picker_panel_split-bordervar(--semi-color-border)时间选择器菜单分割线颜色
$color-timePicker_range_panel-borderrgba(0, 0, 0, 0.1)时间选择器描边颜色
$width-timePicker_range_panel-border1px时间选择器菜单分割线宽度
$height-timePicker_panel_body252px时间选择器菜单高度
$width-timePicker_panel_list_ampm72px时间选择器菜单中列宽度 - 上午下午
$width-timePicker_panel_list_hour64px时间选择器菜单中列宽度 - 小时
$width-timePicker_panel_list_minute64px时间选择器菜单中列宽度 - 分钟
$width-timePicker_panel_list_second64px时间选择器菜单中列宽度 - 秒
$width-timePicker_range_panel_scrolllist_body-border2px时间范围选择器双排菜单中间分割线宽度
$spacing-timePicker_range_panel_scrolllist_header_body-padding0时间范围选择器菜单header与内容内边距
$radius-timePicker_range_panelvar(--semi-border-radius-medium)时间范围选择器菜单圆角
$radius-timePicker_inputvar(--semi-border-radius-small)时间范围选择器圆角
$shadow-timePicker_range_panelvar(--semi-shadow-elevated)时间范围选择器菜单阴影