Element Plus TimePicker 时间选择器完全指南:从基础用法到 API 全解析
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
时间选择器(TimePicker)是 Element Plus 组件库中用于时间输入的交互组件,本文基于官方文档 docs/en-US/component/time-picker.md 并结合仓库源码,系统讲解任意时间选择、时间范围限制、区间选择三大核心场景,以及 Attributes、Events、Exposes 的完整 API 说明与底层实现原理。阅读完本文,你将能够熟练配置disabled-hours/minutes/seconds、arrow-control、is-range等关键属性,理解format与value-format的作用边界,并掌握在 Vue 3 项目中直接落地的完整示例代码。
基础用法:任意时间选择
TimePicker 最基础的形态是选择一个任意时刻,只需引入el-time-picker组件并通过v-model绑定值即可。以下示例来自仓库文档示例 docs/examples/time-picker/basic.vue:
<template> <div class="example-basic"> <el-time-picker v-model="value1" placeholder="Arbitrary time" /> <el-time-picker v-model="value2" arrow-control placeholder="Arbitrary time" /> </div> </template> <script lang="ts" setup> import { ref } from 'vue' const value1 = ref() const value2 = ref() </script>从源码结构看,ElTimePicker组件(packages/components/time-picker/src/time-picker.tsx)内部由三层协作构成:
- 外层
Picker(common/picker.vue)负责输入框、下拉浮层(popper)与焦点管理等公共逻辑; - 面板组件
TimePickPanel(time-picker-com/panel-time-pick.vue)负责单值模式的时间面板; - 核心滚动列表
BasicTimeSpinner(time-picker-com/basic-time-spinner.vue)渲染时、分、秒三个可滚动列。
默认情况下,用户可以在面板中滚动鼠标滚轮来快速切换时分秒。当设置了arrow-control属性后,面板会切换为箭头按钮模式:每个时间列上下各出现一个箭头图标,按住可连续增减数值,更适合触屏或对鼠标滚轮不友好的场景。这一分支逻辑在basic-time-spinner.vue中以v-if="!arrowControl"和v-if="arrowControl"两个模板分支实现,箭头模式还复用了@element-plus/directives提供的v-repeat-click指令来支持长按连发。
限制时间范围:禁用不可选的时间点
如果业务要求只能选择某个时间段内的时刻,可以通过disabled-hours、disabled-minutes、disabled-seconds三个函数属性来精确禁用小时、分钟、秒。以下示例来自 docs/examples/time-picker/basic-range.vue,它把可选项限制在 17:30 到 18:30 之间:
<template> <div class="example-basic"> <el-time-picker v-model="value1" :disabled-hours="disabledHours" :disabled-minutes="disabledMinutes" :disabled-seconds="disabledSeconds" placeholder="Arbitrary time" /> </div> </template> <script lang="ts" setup> import { ref } from 'vue' const value1 = ref(new Date(2016, 9, 10, 18, 30)) const makeRange = (start: number, end: number) => { const result: number[] = [] for (let i = start; i <= end; i++) { result.push(i) } return result } const disabledHours = () => { return makeRange(0, 16).concat(makeRange(19, 23)) } const disabledMinutes = (hour: number) => { if (hour === 17) { return makeRange(0, 29) } if (hour === 18) { return makeRange(31, 59) } return [] } const disabledSeconds = (hour: number, minute: number) => { if (hour === 18 && minute === 30) { return makeRange(1, 59) } return [] } </script>三个函数的签名与调用约定如下(类型定义见 common/props.ts 与 props/shared.ts):
| 属性 | 签名 | 返回 | 说明 |
|---|---|---|---|
disabledHours | (role: string, comparingDate?: Dayjs) => number[] | 被禁用的小时数组 | role在区间模式中为'start'/'end',用于区分起始/结束面板 |
disabledMinutes | (hour: number, role: string, comparingDate?: Dayjs) => number[] | 被禁用的分钟数组 | 根据当前选中的小时动态决定禁用的分钟 |
disabledSeconds | (hour: number, minute: number, role: string, comparingDate?: Dayjs) => number[] | 被禁用的秒数组 | 根据小时和分钟组合动态决定禁用的秒 |
从实现上看,basic-time-spinner.vue通过getTimeLists(定义于 composables/use-time-picker.ts)将这些函数转化为每一列的可选项列表,被禁用的选项会加上is-disabledclass 且点击无效。上例的效果是:17:30 之后、18:30 之前的时间可选,其余时刻的时分秒均被置灰。
提示:在区间模式中,
comparingDate参数还会携带当前正在比较的对面端点日期,可据此实现"结束时间不能早于开始时间"这类联动限制。
区间选择:任意时间范围
通过is-range属性可以让 TimePicker 切换为区间模式,一次选择起止两个时间点,输入框会显示为"起始时间 - 结束时间"的双输入形态。以下示例来自 docs/examples/time-picker/range.vue:
<template> <div class="demo-range"> <el-time-picker v-model="value1" is-range range-separator="To" start-placeholder="Start time" end-placeholder="End time" /> <el-time-picker v-model="value2" is-range arrow-control range-separator="To" start-placeholder="Start time" end-placeholder="End time" /> </div> </template> <script lang="ts" setup> import { ref } from 'vue' const value1 = ref<[Date, Date]>([ new Date(2016, 9, 10, 8, 40), new Date(2016, 9, 10, 9, 40), ]) const value2 = ref<[Date, Date]>([ new Date(2016, 9, 10, 8, 40), new Date(2016, 9, 10, 9, 40), ]) </script>区间模式下的几个关键点:
v-model绑定的值必须是长度为 2 的数组,例如[Date, Date]、[number, number]或[string, string],分别对应绑定值为 Date 对象、时间戳、格式化字符串三种形态;range-separator自定义两个输入框之间的分隔符,默认是'-';start-placeholder与end-placeholder分别设置起始框和结束框的占位文本;arrow-control同样支持区间模式。
在源码中,is-range决定了两件事(见 time-picker.tsx):内部 type 标记为'timerange',面板组件切换为TimeRangePanel(time-picker-com/panel-time-range.vue);区间触发输入框则由 common/picker-range-trigger.vue 渲染。
Attributes 属性总览
以下属性表完整继承自官方文档,并补充了取值范围说明。除非特别标注版本,属性在当前版本中均可用:
| 名称 | 说明 | 类型 | 默认值 |
|---|---|---|---|
model-value/v-model | 绑定值,若为数组则长度应为 2 | number/string/Date/[Date, Date]/[number, number]/[string, string] | '' |
readonly | 是否只读 | boolean | false |
disabled | 是否禁用 | boolean | false |
editable | 输入框是否可编辑 | boolean | true |
clearable | 是否显示清除按钮 | boolean | true |
size | 输入框尺寸 | 'large' \| 'default' \| 'small' | — |
placeholder | 非区间模式的占位文本 | string | '' |
start-placeholder | 区间模式起始框占位文本 | string | — |
end-placeholder | 区间模式结束框占位文本 | string | — |
is-range | 是否选择时间区间 | boolean | false |
arrow-control | 是否使用箭头按钮选择时间 | boolean | false |
popper-class | 下拉浮层自定义类名 | string | '' |
popper-style | 下拉浮层自定义样式 | string/object | — |
popper-options | 自定义 popper 配置项(基于 Popper.js 的Partial<PopperOptions>) | object | {} |
fallback-placements(2.8.4) | 浮层兜底位置列表 | Placement[] | ['bottom', 'top', 'right', 'left'] |
placement(2.8.4) | 浮层弹出位置 | Placement | bottom |
range-separator | 区间分隔符 | string | '-' |
format | 输入框中显示值的格式,参见 date-formats | string | — |
default-value | 日历默认日期(可选) | Date/[Date, Date] | — |
value-format | 绑定值的格式;不指定时绑定值为 Date 对象,参见 date-formats | string | — |
id | 原生 input 的id | string/[string, string] | — |
name | 原生 input 的name | string | '' |
aria-label(a11y,2.7.2) | 原生 input 的aria-label | string | — |
prefix-icon | 自定义前缀图标组件 | string/Component | Clock |
clear-icon | 自定义清除图标组件 | string/Component | CircleClose |
disabled-hours | 指定不可选的小时数组 | (role: string, comparingDate?: Dayjs) => number[] | — |
disabled-minutes | 指定不可选的分钟数组 | (hour: number, role: string, comparingDate?: Dayjs) => number[] | — |
disabled-seconds | 指定不可选的秒数组 | (hour: number, minute: number, role: string, comparingDate?: Dayjs) => number[] | — |
teleported | 下拉浮层是否传送(teleport)到 body | boolean | true |
tabindex | 输入框 tabindex | string/number | 0 |
empty-values(2.7.0) | 组件的空值集合,参见 config-provider 空值配置 | array | — |
value-on-clear(2.7.0) | 清空时的返回值,参见 config-provider 空值配置 | string/number/boolean/Function | — |
save-on-blur(2.13.4) | 聚焦时若未选择值,失焦是否自动填入当前时间 | boolean | true |
label(a11y,已废弃) | 原生 input 的aria-label(已被aria-label取代) | string | — |
其中几个值得深入说明的属性:
format与value-format的区别。format只影响输入框的显示文本;value-format才决定v-model绑定值的数据形态。默认展示格式为HH:mm:ss(常量定义于 constants.ts),由DEFAULT_FORMATS_TIME提供。若设置了value-format(如'HH:mm:ss'),绑定值将变为字符串;若不设置,绑定值为Date对象。格式化与解析分别通过formatter与parseDate完成,二者位于 utils.ts,底层依赖 dayjs 的customParseFormat插件(在 time-picker.tsx 中显式dayjs.extend(customParseFormat))。
popper-options/popper-class/popper-style/placement/fallback-placements。这些属性共同控制下拉浮层的行为与外观。popperOptions在 time-picker.tsx 中通过provide(PICKER_POPPER_OPTIONS_INJECTION_KEY, props.popperOptions)注入到 Popper 体系;placement与fallbackPlacements定义于 common/props.ts,其合法值取自 Popper.js 的placements枚举。注意:浮层相关链接指向外部文档,本文不展开,具体行为以 Popper.js 官方规范为准。
empty-values与value-on-clear。这两个 2.7.0 新增属性与全局 ConfigProvider 的空值策略联动,用于统一"哪些值算空值"以及"清空后回填什么值",适用于全项目需要统一空值语义的场景。
save-on-blur。2.13.4 新增,默认true。它控制一个细节行为:聚焦时间面板但未做任何选择时,失焦后输入框是否自动填入当前系统时间。若设为false,失焦后输入框保持为空。
Events 事件
| 名称 | 说明 | 类型 |
|---|---|---|
change | 用户确认值时触发 | (val: number \| string \| Date \| [number, number] \| [string, string] \| [Date, Date]) => void |
blur | 输入框失焦时触发 | (e: FocusEvent) => void |
focus | 输入框聚焦时触发 | (e: FocusEvent) => void |
clear(2.7.7) | 可清除的 TimePicker 中点击清除图标时触发 | () => void |
visible-change | 下拉浮层出现/消失时触发 | (visibility: boolean) => void |
change事件的值形态与value-format设置强相关:不设置value-format时回调中收到的是Date对象(区间模式为[Date, Date]),设置后则是格式化字符串或时间戳。visible-change常用于在面板展开/收起时联动其他 UI 逻辑,例如收起后同步外部统计或重置状态。
Exposes 暴露的方法
TimePicker 通过模板引用(template ref)暴露以下方法,可在父组件中通过ref获取组件实例后调用:
| 名称 | 说明 | 类型 |
|---|---|---|
focus | 聚焦 TimePicker 组件 | () => void |
blur | 使 TimePicker 组件失焦 | () => void |
handleOpen(2.2.16) | 打开 TimePicker 浮层 | () => void |
handleClose(2.2.16) | 关闭 TimePicker 浮层 | () => void |
这四个方法在 time-picker.tsx 中通过ctx.expose暴露,内部全部委托给公共Picker实例(commonPicker)的同名方法。典型用法示例:
<template> <el-time-picker ref="pickerRef" v-model="value" /> <el-button @click="pickerRef?.handleOpen()">打开时间面板</el-button> </template> <script lang="ts" setup> import { ref } from 'vue' import type { TimePickerInstance } from 'element-plus' const pickerRef = ref<TimePickerInstance>() const value = ref() </script>源码结构解读:TimePicker 的分层设计
结合前文各部分,TimePicker 在仓库中的完整结构如下(packages/components/time-picker):
src/ ├── common/ # 公共逻辑 │ ├── picker.vue # 输入框 + 浮层 + 焦点管理 │ ├── picker-range-trigger.vue # 区间模式双输入触发框 │ └── props.ts # 组件全部默认属性定义 ├── composables/ # 组合式函数 │ ├── use-common-picker.ts # 公共 picker 逻辑 │ ├── use-time-panel.ts # 面板联动逻辑 │ └── use-time-picker.ts # 时/分/秒禁用列表计算 ├── props/ # 分块属性定义 │ ├── basic-time-spinner.ts │ ├── panel-time-picker.ts │ ├── panel-time-range.ts │ └── shared.ts # disabledTimeListsProps 等共享属性 ├── time-picker-com/ # 面板组件 │ ├── basic-time-spinner.vue # 时/分/秒滚动列核心 │ ├── panel-time-pick.vue # 单值面板 │ └── panel-time-range.vue # 区间面板 ├── constants.ts # 默认格式、注入 key 等常量 ├── time-picker.tsx # ElTimePicker 主组件 └── utils.ts # 格式化/解析/日期比较工具值得注意的设计细节:
- 禁用列表的链式计算:
disabledMinutes接收disabledHours的选中结果,disabledSeconds再接收前两者的结果,逐级收敛可选范围,最终由getTimeLists汇总为三个列的禁用状态数组。 - 滚动与箭头双模式复用同一数据源:
basic-time-spinner.vue中滚动模式使用el-scrollbar渲染完整列表并支持滚轮,箭头模式则通过buildTimeList(utils.ts)只渲染当前值的前一个/当前/后一个三个候选值,配合v-repeat-click实现按住连加连减。 - 属性驱动的组件组合:主组件
ElTimePicker只做"根据is-range选择面板组件"这一件事,其余全部逻辑下沉到公共Picker,这也解释了为何is-range可以在属性表中单独成行而面板切换对用户完全透明。 - 测试保障:仓库在 packages/components/time-picker/tests/time-picker.test.tsx 中对该组件的绑定、禁用、区间、事件等行为有完整的单元测试覆盖,可作为自定义扩展时的行为参照。
总结
Element Plus 的 TimePicker 以"任意时间选择 → 时间范围限制 → 区间选择"三个层次覆盖了绝大多数时间输入场景:基础用法配合arrow-control应对滚轮与按钮两种交互习惯;disabled-hours/minutes/seconds提供逐级精确的可选区间控制;is-range一键切换为起止时间双输入。配合format/value-format控制显示与绑定形态、save-on-blur、empty-values等精细属性,以及focus/handleOpen等暴露方法,足以支撑表单校验、预约时段、排班配置等各类实战需求。
【免费下载链接】element-plus🎉 A Vue.js 3 UI Library made by Element team项目地址: https://gitcode.com/GitHub_Trending/el/element-plus
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考