news 2026/10/23 15:37:02

Arco Design TimePicker 时间选择器:完整 API、范围选择与时区实现解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Arco Design TimePicker 时间选择器:完整 API、范围选择与时区实现解析
  • UI组件
  • 前端
  • 设计系统

【免费下载链接】arco-design

A comprehensive React UI components library based on Arco Design

项目地址:https://gitcode.com/gh_mirrors/ar/arco-design
点击查看免费下载

Arco Design(arco-design)的TimePicker是一个"在弹出面板上选择时间,以便捷完成时间输入"的组件,覆盖单值时间选择与RangePicker时间段选择两类场景。本文以官方英文文档TimePicker的 API 说明为主体,逐条解析其通用属性、单值与范围属性的语义、默认值与版本演进,并结合组件源码(components/TimePicker目录下的picker.tsx、time-picker.tsx、range-picker.tsx、time-column.tsx、util.ts)与测试用例,说明列生成、滚动吸附、确认流程、时区转换等底层实现机制,帮助你既会用、又懂其原理。

一、组件构成与基本用法

1.1 导出结构

从源码 index.tsx 看,组件通过一个wrapper高阶函数把内部面板(TimePickerPopup/RangePickerPopup)包裹进通用的Picker壳:

const TimePicker = wrapper<TimePickerProps>(<TimePickerPopup />, 'TimePicker'); const RangePicker = wrapper<RangePickerProps>( <RangePickerPopup />, 'TimePickerRangePicker', 'range' ); Object.assign(TimePicker, { RangePicker });

因此对外只导出一个TimePicker,RangePicker作为静态属性挂载,即TimePicker.RangePicker。类型定义中TimePickerDecorator接口(见 interface.tsx)明确了这一结构:TimePickerProps = BaseTimePickerProps & PickerProps,RangePickerProps = BaseRangePickerProps & PickerProps——即单值与范围选择器共享同一套PickerProps通用属性,这正是文档将 API 分为 "Picker / TimePicker / TimePicker.RangePicker" 三张表的原因。

1.2 基础用法

来自示例 basic.md:

import { TimePicker } from '@arco-design/web-react'; const App = () => { return <TimePicker style={{ width: 194 }} />; }; export default App;

默认格式为HH:mm:ss(24 小时制),面板包含时/分/秒三列,底部有"此刻"与"确定"两个按钮。这一点可由单元测试 index.test.tsx 印证:基础渲染断言了三列.arco-timepicker-list与两个底部按钮,且三列单元格数分别为 24、60、60。

二、API 全量参考(以官方文档为准)

2.1 Picker:TimePicker 与 RangePicker 的通用属性

参数名描述类型默认值版本
allowClear是否显示清除按钮booleantrue-
disableConfirm禁用确认步骤,开启后直接点选时间无需点击确认按钮boolean-2.12.0
disabled是否禁用boolean--
editable输入框是否可手动输入booleantrue-
error是否错误状态(已废弃,下个大版本移除,请用status='error'替代)boolean--
hideDisabledOptions隐藏禁止选择的选项boolean--
popupVisible受控弹出框的显示/隐藏boolean--
scrollSticky时间列滚动时自动吸附并选中booleantrue2.23.0
unmountOnExit关闭后是否销毁弹层 DOMboolean--
use12Hours12 小时制显示,默认格式h:mm:ss aboolean--
utcOffset时区偏移;如需 UTC 时间则设为0number--
format时间展示格式(dayjs 占位符)stringHH:mm:ss-
timezone时区名称;若设置了utcOffset,以utcOffset为准string--
position弹层位置'top' \| 'tl' \| 'tr' \| 'bottom' \| 'bl' \| 'br'bl-
size输入框尺寸'mini' \| 'small' \| 'default' \| 'large'--
status状态'error' \| 'warning'-2.45.0
extra底部附加内容ReactNode--
prefix前缀ReactNode-2.43.0
triggerElement自定义触发元素ReactNode-2.38.0
className附加 CSS 类名string \| string[]--
icons图标配置{ inputSuffix?: ReactNode }--
placeholder输入框提示文案string \| string[]--
step时/分/秒的选择间隔{ hour?: number; minute?: number; second?: number }--
style附加样式CSSProperties--
triggerProps透传给Trigger组件的参数Partial<TriggerProps>--
disabledHours禁用的部分小时选项() => number[]--
disabledMinutes禁用的部分分钟选项(selectedHour) => number[]--
disabledSeconds禁用的部分秒数选项(selectedHour, selectedMinute) => number[]--
getPopupContainer弹层挂载的父节点(node: HTMLElement) => Element--
onClear点击清除按钮的回调() => void--

triggerProps最终透传给 Trigger 组件,可控制弹层的更多行为(如autoAlignPopupWidth,见后文时区示例)。

默认值在源码中的落点:picker.tsx 中定义了defaultProps,并通过useMergeProps与componentConfig?.TimePicker(即ConfigProvider的componentConfig)三层合并:

const defaultProps: InnerPickerProps = { allowClear: true, position: 'bl', format: 'HH:mm:ss', editable: true, order: true, scrollSticky: true, };

这意味着默认值不仅写死在组件里,还可被ConfigProvider的全局componentConfig统一覆盖。另外,在 RTL(从右到左)布局下源码会把默认position从'bl'调整为'br',适配右起语言的弹层方位。

2.2 TimePicker 单值属性

参数名描述类型默认值版本
showNowBtn是否显示"此刻"(当前时间)按钮booleantrue2.21.0
defaultValue默认时间CalendarValue--
value组件的值,受控模式CalendarValue--
onChange选择时间后的回调(值变化时触发)(valueString: string, value: Dayjs) => void--
onSelect选择时间时的回调(面板内选择即触发)(valueString: string, value: Dayjs) => void--

onSelect与onChange的区别在源码中非常清晰:面板内每点选一个时间单元都会先触发onSelect(见 time-picker.tsx 的onHandleSelect),而onChange只在点击"确定"(或disableConfirm时点选即确认)且值真正变化后由Picker层的onHandleChange触发,并用isDayjsChange做了变化检测,避免无效回调。

2.3 TimePicker.RangePicker 范围属性

参数名描述类型默认值版本
order起止时间是否自动排序booleantrue2.21.0
defaultValue默认时间CalendarValue[]--
placeholder输入框提示文案string[]--
value组件的值,受控模式CalendarValue[]--
onChange值改变时的回调(valueString: string[], value: Dayjs[]) => void--
onSelect选择时间时的回调(valueString: string[], value: Dayjs[]) => void--

2.4 CalendarValue 类型

export type CalendarValue = Dayjs | Date | string | number;

即defaultValue/value接受Dayjs、Date、字符串或时间戳四种形式。源码 picker.tsx 中getDefaultValue()会先经过公共工具getDayjsValue(见 _util/dayjs.ts)统一归一化为Dayjs:字符串会先按当前format解析,失败后依次尝试内置的多种回退格式,保证"18:24:23"、"18:24"等常见写法都能被识别。

三、典型场景与可复制示例

以下示例均取自官方 demo 目录(components/TimePicker/demo),可直接运行。

3.1 受控组件

value与onChange需配合使用(control.md):

import { useState } from 'react'; import { TimePicker } from '@arco-design/web-react'; function App() { const [value, setValue] = useState(); return ( <TimePicker style={{ width: 194 }} value={value} onChange={(valueString) => setValue(valueString)} /> ); }

源码中受控/非受控的判定是'value' in props ? getDayjsValue(propsValue, ...) : value——只要显式传入value(哪怕是undefined),即视为受控。测试用例(index.test.tsx 中 "set to undefined and onChange correctly",对应 issue #358)验证了受控值从具体时间重置为undefined后输入框清空、再次选择仍能正确触发onChange。

3.2 默认值

defaultValue.md:

import { TimePicker } from '@arco-design/web-react'; const { RangePicker } = TimePicker; const App = () => { return ( <div> <TimePicker defaultValue="18:24:23" style={{ width: 194 }} /> <RangePicker defaultValue={['09:24:53', '18:44:33']} style={{ width: 252 }} /> </div> ); };

3.3 定制格式 format

format决定输入框展示,同时决定面板渲染哪些列。format.md:

import { TimePicker } from '@arco-design/web-react'; import dayjs from 'dayjs'; const App = () => ( <TimePicker format="HH:mm" defaultValue={dayjs('09:24', 'HH:mm')} style={{ width: 130 }} /> );

实现依据是 util.ts 中的getColumnsFromFormat:它扫描格式串中的H、h、m、s、a、A占位符,只渲染对应列;若出现a/A还自动推断为 12 小时制(此时可不显式传use12Hours)。测试用例 "format" 验证了format="HH:mm"时面板只有时、分两列。

3.4 定制步长 step

step.md:

const App = () => ( <TimePicker defaultValue="10:25:30" step={{ hour: 2, minute: 5, second: 10 }} style={{ width: 194 }} /> );

源码time-picker.tsx的getShowList按步长生成选项:小时列为0, 2, 4, ..., 22,分钟列为0, 5, ..., 55,秒列为0, 10, ..., 50;12 小时制下小时列仅 12 项且首项改写为12。单测 "step" 断言三列单元格数恰为 12、12、6,与24/2、60/5、60/10完全一致。

3.5 12 小时制 use12Hours

use-12-hours.md:

import { TimePicker } from '@arco-design/web-react'; import dayjs from 'dayjs'; const App = () => ( <div> <TimePicker use12Hours format="hh:mm:ss A" defaultValue={dayjs('12:20:20 AM', 'hh:mm:ss A')} placeholder="请选择时间" style={{ width: 194 }} /> <TimePicker.RangePicker use12Hours format="hh:mm:ss A" defaultValue={[dayjs('12:20:20 AM', 'hh:mm:ss A'), dayjs('08:30:30 PM', 'hh:mm:ss A')]} style={{ width: 300 }} /> </div> );

启用后面板会额外出现一列am/pm选择列(renderAmPm),其大小写跟随格式串中的A/a占位符。RangePicker 的单测(range.test.tsx)验证了 12 小时制下会多渲染第 4 列且仅 2 个单元格(am/pm)。

3.6 禁用与隐藏部分时间选项

disabledTime.md:

const App = () => ( <div> <TimePicker style={{ width: 194 }} disabledHours={() => [1, 2, 4, 14]} disabledMinutes={() => [1, 2, 3, 4, 14, 15, 16, 20, 50]} disabledSeconds={() => [1, 2, 3, 4, 5, 6, 7, 10, 14, 60]} /> </div> );

注意三个回调的签名差异:disabledHours无参数;disabledMinutes(selectedHour)与disabledSeconds(selectedHour, selectedMinute)可依据上级列的当前选择做联动禁用。

源码还有两个值得了解的行为:

  1. 选中值联动纠正:在onHandleSelect中,若用户切换小时后当前分钟/秒落入新小时的禁用集合,组件会自动改为该范围内第一个未禁用的值,而不是产生非法组合;
  2. 默认值避开禁用项:getDefaultStr在无初始值时,会选取"第一个未禁用的选项"作为各列默认展示。这修复了早期版本的已知缺陷——变更日志 index.zh-CN.md 记载 2.51.1 "修复选中默认值没有兼容disabledHoursdisabledMinutesdisabledSeconds的 bug",测试用例 "should get non-disabled value as default"(对应 issue #494)断言最终值为03:00:01(0、1、2 时与 0、1 分均被禁用的场景)。

配合hideDisabledOptions可进一步直接隐藏禁用项(渲染时先filter再建列)。单测 "disabledHours / disabledMinutes / disabledSeconds" 断言了三列中禁用样式单元格数分别为 4、9、9。

3.7 禁用确认 disableConfirm

disableConfirm.md:

const App = () => ( <div> <TimePicker disableConfirm onSelect={(v, vd) => console.log('onSelect', v, vd)} onChange={(v, vd) => console.log('onChange', v, vd)} style={{ width: 194 }} /> <TimePicker.RangePicker disableConfirm onSelect={onSelect} onChange={onChange} style={{ width: 252 }} /> </div> );

开启后底部确认按钮不再渲染,点选时间列即视为确认(onHandleSelect末尾直接调用onConfirmValue)。源码中页脚渲染逻辑_hideFooter表明:disableConfirm且单值模式且showNowBtn=false时整个页脚都会被隐藏。单测 "disableConfirm" 验证了点选第 2 个小时后输入框直接变为01:00:00且onChange立即触发。

3.8 范围选择器 RangePicker

rangepicker.md:

const App = () => ( <TimePicker.RangePicker style={{ width: 252 }} onSelect={(valueString, value) => console.log('onSelect:', valueString, value)} onChange={(valueString, value) => console.log('onChange:', valueString, value)} /> );

范围模式的交互细节在 range-picker.tsx 中实现:

  • 面板复用单值TimePicker,只展示"聚焦输入框"对应的那一个值,通过focusedInputIndex与changeFocusedInputIndex在两个输入框间切换焦点;
  • 任一输入框未填时"确定"按钮保持禁用(confirmBtnDisabled={!isDayjs(currentShowValue)}),点击确定若发现有一项为空,会自动把焦点切换到另一侧输入框而非报错;
  • 最终onConfirmValue在Picker层处理:order(默认true)为真时对两个值调用getSortedDayjsArray(dayjs.ts)按时间戳升序排序后再落值并触发onChange,保证回调参数始终是[start, end]。

3.9 时区与 UTC 时间

时区由timezone(IANA 时区名)或utcOffset(偏移量)控制,二者同设时utcOffset优先。官方 demo(timezone.md、utcOffset.md)特别强调:使用 UTC 或时区时间时,传值请用 timestamp 或 Date 对象,字符串无法表示唯一时间,会造成困扰。

import { TimePicker, Select } from '@arco-design/web-react'; const zoneList = ['America/Los_Angeles', 'Europe/London', 'Africa/Cairo', 'Asia/Shanghai']; function App() { const [timezone, setTimezone] = useState('Asia/Shanghai'); const [value, setValue] = useState(new Date('2022-02-22')); return ( <Space> <Select defaultValue={timezone} options={zoneList} onChange={(tz) => setTimezone(tz)} triggerProps={{ autoAlignPopupWidth: false, position: 'bl' }} /> <TimePicker timezone={timezone} defaultValue={value} onChange={(v, vd) => setValue(vd && vd.toDate())} /> </Space> ); }

实现原理在 _util/dayjs.ts:内部用toTimezone/toLocal做时区偏移换算(含对夏令时/冬令时边界的微调修正),getDayjsValue在设置了utcOffset/timezone时会把外部传入的值先转换到目标时区;而回调onChange返回前统一经toLocal转回本地时间。时区/偏移通过 context.ts 的PickerContext从Picker壳下发给面板层,Picker层还会监听utcOffset/timezone变化(usePrevious对比前后值),动态把已存储的值重新换算,保证切换时区时显示值正确。该能力自 2.30.0 引入。

3.10 其他外观类属性

  • status(status.md):<TimePicker status="error" />/status="warning",2.45.0 起替代已废弃的error布尔属性;
  • prefix(prefix.md):<TimePicker prefix={<IconInfoCircle />} />,2.43.0 引入;
  • extra(extra.md):<TimePicker extra="Extra Footer" />,在列区与页脚按钮之间渲染附加节点(time-picker.tsx中.arco-timepicker-footer-extra-wrapper);
  • size(size.md):'mini' | 'small' | 'default' | 'large'四种尺寸;
  • disabled(disabled.md):整组件禁用,Trigger不再响应点击。

四、面板底层机制

4.1 列渲染与滚动吸附

单列时间选项由TimeColumn(time-column.tsx)渲染,scrollSticky(默认true,2.23.0 引入)的行为是:

  • 监听onWheel,经 100ms 防抖后按当前scrollTop计算吸附索引(向上滚用Math.ceil、向下滚用Math.floor),自动选中该索引处且未禁用的选项;scrollSticky={false}时完全不绑定onWheel(2.49.1 修复过此时控制台出现 warning 的 bug);
  • 选中值变化时通过scrollTo(util.ts)以b-tween的quartInOut缓动做 150ms 平滑滚动定位;弹层每次打开则瞬间(duration 0)滚动到当前值。

4.2 确认流程与页脚按钮

time-picker.tsx的页脚渲染逻辑:

const _hideFooter = hideFooter || (disableConfirm && isRangePicker) || (!isRangePicker && disableConfirm && !showNowBtn);
  • 单值模式默认显示locale.TimePicker.now("此刻"按钮,showNowBtn默认true,2.21.0 引入)与"确定"按钮;
  • "此刻"按钮通过getNow(utcOffset, timezone)取当前时间(设置了时区时会取目标时区的"现在",见 dayjs.ts 的getNow),并触发onSelect;
  • "确定"按钮在confirmBtnDisabled || !valueShow时禁用,即必须已有面板内选择才可确认;
  • 键盘回车(onPressEnter)等价于点击"确定":单值直接确认,Range 模式下先检查输入框合法字符串、焦点切换,两个值齐全后才确认(picker.tsx)。

4.3 triggerElement:自定义触发器与纯面板模式

triggerElement(2.38.0 引入)替换默认的输入框触发器。源码中有一个特殊分支:triggerElement === null时直接渲染面板本身(renderPopup(true)),即"只用面板、不用触发器"的纯面板模式——变更日志(2.44.0)明确记载了这一特性。若传入自定义节点,则节点被包在Trigger内作为点击触发源,triggerProps继续透传Trigger的其他参数(如autoAlignPopupWidth)。

五、版本演进与使用注意事项

从 变更日志 可梳理出该组件的能力时间线:

版本变更
2.12.0新增disableConfirm,支持点选即确认
2.21.0TimePicker新增showNowBtn;RangePicker新增order自动排序
2.23.0新增scrollSticky滚动吸附开关
2.30.0支持utcOffset与timezone
2.38.0新增triggerElement自定义触发器
2.43.0新增prefix
2.44.0支持triggerElement={null}纯面板模式
2.45.0新增status(error属性同期标记废弃)
2.51.1修复默认值未兼容disabled*选项的 bug

使用建议小结:

  1. format是核心参数——它同时决定展示格式、面板列构成、12 小时制推断,写值格式(HH:mm或hh:mm:ss A)应与期望粒度一致;
  2. 时区/UTC 场景请传Date或时间戳,不要用字符串表达"某时区的时间";切换时区时组件会自动换算已有值;
  3. onSelect与onChange分工:前者是"面板操作反馈",后者是"最终值确认",表单提交逻辑应挂在onChange;
  4. disableConfirm适合"点选即生效"的快捷场景,此时onChange在每次点选后触发;
  5. RangePicker的order默认开启,回调中拿到的永远是排序后的[start, end],不需要自行排序。

本文所有 API 语义以官方文档components/TimePicker/README.en-US.md(及对应中文版 README.zh-CN.md)为准,实现细节可继续在 TimePicker 源码目录、公共 dayjs 工具 与 测试用例 中查证。

  • UI组件
  • 前端
  • 设计系统

【免费下载链接】arco-design

A comprehensive React UI components library based on Arco Design

项目地址:https://gitcode.com/gh_mirrors/ar/arco-design
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/23 17:59:31

从SD卡驱动入门Linux驱动开发:协议、框架与调试实战

1. 为什么从 SD 卡驱动入手想要理解 Linux 驱动开发&#xff0c;很多人第一反应是去啃字符设备、平台总线、设备树这些概念。但我个人的建议是&#xff1a;直接从 SD 卡/SDIO 驱动入手。理由很简单&#xff0c;SD 卡驱动几乎涵盖了 Linux 驱动开发的全部核心要素&#xff1a;总…

作者头像 李华
网站建设 2026/10/23 18:00:12

TCSP练习题:时间约束调度建模与CP-SAT求解实战

简介&#xff1a;本资源为TCSP&#xff08;网络安全专业&#xff09;核心知识点配套练习题集&#xff0c;面向高校信息安全、网络工程专业学生及备考网络安全认证的学习者&#xff0c;聚焦网络攻击类型辨析、防火墙技术对比、入侵检测原理、加密与数字证书机制等关键考点&#…

作者头像 李华
网站建设 2026/10/22 15:41:02

如何将OpenTag部署到Railway:双服务生产架构完整教程

【免费下载链接】OpenTag OpenTag: The Channels SDK starter application, a self-hosted AI on-call triage bot for Slack and Microsoft Teams, built with AG-UI and LangGraph. Fork it and ship your own. 项目地址&#xff1a; https://gitcode.com/gh_mirrors/open/Op…

作者头像 李华
网站建设 2026/10/23 7:04:43

墙面跟踪遇到遮挡后漂移:分段重建位置,再核连续运动

平面跟踪总是跟丢&#xff0c;可以在剪映当前支持的平面跟踪流程先找最早漂移位置&#xff0c;按遮挡和镜头变化切分区间&#xff0c;再用有效平面重新定位。街头墙面贴文字时&#xff0c;行人经过、光线变化或纹理不足都可能影响结果&#xff1b;只把最后一帧拉回墙上&#xf…

作者头像 李华
网站建设 2026/10/19 8:38:33

T400白名单配置三层次原理与实战避坑指南

简介&#xff1a;本资源是一份针对ThinkPad T400笔记本的BIOS白名单修改实战指南&#xff0c;面向硬件爱好者、黑苹果玩家及有一定动手能力的Windows/Linux双系统用户&#xff0c;解决因主板白名单限制导致新型无线网卡&#xff08;如Atheros AR9289&#xff09;无法识别、系统…

作者头像 李华