资讯动态

Varlet TimePicker 时间选择器:从交互原理到完整 API 的实战指南

发布时间:2026/10/14 17:16:31 来源:尧图企业网站定制
UI组件前端【免费下载链接】varletA Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.项目地址https://gitcode.com/gh_mirrors/va/varlet点击查看免费下载Varlet 是一个基于 Material Design 的 Vue 3 组件库其中的 TimePicker时间选择器采用仿手表表盘的圆形时钟交互来选取时、分、秒。本文以 Varlet 官方的 TimePicker 文档 为主线完整覆盖其全部用法示例与 API并结合 TimePicker.vue、clock.vue 等源码深入解析触摸角度计算、时/分/秒面板切换与时间限制min/max/allowed-time的底层判定逻辑读完即可掌握该组件的正确接入方式与定制手段。组件结构与基本使用TimePicker 通过v-model双向绑定被选择的时间值为 ISO 8601 风格的字符串HH:mm或HH:mm:ss。基本用法如下script setup import { ref } from vue const date ref(11:20) /script template var-time-picker v-modeldate / /template组件由两部分组成TimePicker.vue 负责标题栏时间显示、AM/PM 切换、面板切换与触摸事件处理内部的 clock.vue 负责绘制圆盘刻度、指针hand与 24 小时模式的内圈。从 index.ts 可以看到组件通过withInstall与withPropsDefaultsSetter注册既支持全局app.use(TimePicker)测试用例 index.spec.js 第一条即验证了插件安装也支持TimePicker.setPropsDefaults设置属性默认值。几个源码层面的关键事实v-model绑定undefined或空字符串时组件会调用resetTime()将内部状态复位为00:00:00并清除小时角度见 TimePicker.vue 中 watchmodelValue的逻辑标题栏时间按钮点击的是checkPanel(panelType)它只切换typehour/minute/second而不直接取值真正取值发生在clock.vue中 watchactiveItemIndex变化时拼装newTime并emit(update)hint属性缺省时使用 locale 词条timePickerHint中文环境默认为“选择时间”见 locale/zh-CN.ts 与 TimePicker.vue 中的injectLocaleProvider。24 小时格式formatformat用于切换选择器的时间格式可选值为ampm与24hr默认值为ampm12 小时制标题栏右侧带 AM/PM 按钮script setup import { ref } from vue const date ref(15:20) /script template var-time-picker v-modeldate format24hr / /template两种模式在磁盘交互上的差异可以结合源码理解ampm 模式外圈刻度为hoursAmpm [12, 1, 2, ..., 11]共 12 格标题栏渲染 AM/PM 按钮点击触发checkAmpm。当 AM/PM 切换后如果原小时已因限制而不可用findAvailableHour会从当前索引开始顺延查找下一个可用小时见 TimePicker.vue。测试用例 timePicker switch ampm 验证了05:10:22切换 PM 后变为17:10:2224hr 模式外圈仍是 12 个刻度但额外渲染一个内圈hours24 [00, 13, 14, ..., 23]见 props.ts 与 clock.vue 的v-ifformat 24hr type hour分支。用户拖到内圈区域选取 13~23 点、外圈选取 0~11 点由setHourRad通过getInner判断触点是否落在内圈范围内范围由innerRange计算来切换取值集合。注意无论哪种 formatv-model的底层值始终是 24 小时制format 只影响标题栏的显示与表盘刻度取值。显示秒use-secondsuse-seconds开启后标题栏会额外显示秒按钮选分钟时可继续进入秒面板此时v-model值变为HH:mm:ssscript setup import { ref } from vue const date ref(17:36:22) /script template var-time-picker v-modeldate format24hr use-seconds / /template面板推进逻辑在end()touchend 回调中选完小时且该小时可用 → 切到分钟use-seconds开启且分钟可用 → 再切到秒见 TimePicker.vue。秒刻度与分钟相同为minSec [00, 05, 10, ..., 55]即每 5 格 1 个刻度、共 60 格。只读readonlyreadonly开启后组件仅展示当前时间禁止一切交互script setup import { ref } from vue const date ref(07:10) /script template var-time-picker v-modeldate readonly / /template从源码看moveHand与end、checkAmpm三个交互入口均在开头判断props.readonly直接返回见 TimePicker.vue而测试 timePicker readonly 专门模拟了触摸拖动与按钮点击断言标题时间始终保持11:11不变。时间限制min、max 与 allowed-time通过min、max和allowed-time属性可以控制可选择的时间范围script setup import { ref } from vue const date ref(07:10:12) const allowedTime { hours: (hour) hour % 2 0, minutes: (minute) minute % 15 ! 0, seconds: (second) second % 2 ! 0, } /script template var-time-picker v-modeldate format24hr use-seconds min2:28:38 max19:40:22 :allowed-timeallowedTime / /templateAllowedTime的类型定义props.ts 与 types/timePicker.d.ts 一致export type AllowedTime { hours?: (hour: number) boolean minutes?: (minute: number) boolean seconds?: (second: number) boolean }三个字段均可选回调返回true表示该值允许选择。限制在源码中分两层生效小时层clock.vue内 watch[max, min, allowedTime]deep immediate根据三者分别过滤hoursAmpm与hours24合并出被禁用的小时列表disableHour见 clock.vue。只有 min 时禁用小于minHour的小时只有 max 时禁用大于maxHour的小时两者都有则同时过滤两端allowedTime.hours命中的小时再去重合并进来。分/秒层utils.ts 中的getIsDisableMinute/getIsDisableSecond负责边界判定——分钟禁用条件是“当前小时等于 min/max 的小时且分钟越界”秒则进一步细化到“分钟也相等且秒越界”同时若当前小时已在disableHour中分/秒整体禁用。用户拖动表盘时setMinuteRad/setSecondRad会先做禁用判断命中则不更新角度见 TimePicker.vue。测试用例 timePicker max and min 覆盖了 min、max 单独生效与同时为11:11时的锁定行为当上下界重合为同一时刻后任何触摸与点击都无法改变11:11。自定义操作栏actions 插槽通过actions插槽可以在时钟下方放置自定义操作按钮如“取消 / 确定”script setup import { ref } from vue const date ref(17:36:22) /script template var-time-picker v-modeldate template #actions var-space sizesmall var-button typeprimary text操作/var-button var-button typeprimary text操作/var-button /var-space /template /var-time-picker /template插槽无参数渲染条件是$slots.actions存在见 TimePicker.vue外层容器使用.var-time-picker__actions内边距由--time-picker-actions-padding控制。官方示例页 example/index.vue 即采用var-space 两个var-button的写法。触摸交互与角度计算的底层原理TimePicker 的核心体验是“像转手表一样拨动时间”其实现链路如下均见 TimePicker.vueclock-container上监听touchstart/touchmove/touchend统一进入moveHand(event)setCenterAndRange通过getRect拿到容器中心点24hr 模式下还会记录内圈命中范围用触点坐标相对中心的角度Math.atan2(y, x)换算成角度并四舍五入到最近刻度小时Math.round(roundDeg / 30) * 30 9012 格 × 30°分/秒Math.round(roundDeg / 6) * 6 9060 格 × 6°得到新角度后写入hourRad/minuteRad/secondRad由getRad计算属性按当前type下发给clock.vue指针通过transform: rotate(rad)跟随见 clock.vueclock.vuewatchrad/activeItemIndex用dayjs将数值格式化为HH/mm/ss拼装新的时间字符串后emit(update)最终由 TimePicker.vue 的update同时触发onUpdate:modelValue与onChange。刻度项的定位是纯三角函数rad (2π/12) * index - π/2left 50 * (1 cos(rad))、top 50 * (1 sin(rad))百分比布局见 clock.vue因此整个表盘可随容器缩放而自适应。modelValue外部变化时watch 也会把值反向解析为rad小时 × 30、分/秒 × 612 点特判为 0保证受控值与表盘指针同步。API 参考属性参数说明类型默认值v-model被选择的时间ISO 8601 格式HH:mm或HH:mm:ssstring-format选择器时间格式可选值为ampm 24hrstringampmcolor选择器的颜色string-title-color选择器标题栏背景色如果未指定将使用color属性或默认颜色string-hint选择器提示语string选择时间elevation海拔高度可选值为truefalse和0-24的等级string | number | booleanfalsemin允许的最小时间ISO 8601 格式string-max允许的最大时间ISO 8601 格式string-allowed-time限制可以选择的时间AllowedTime-readonly是否只读booleanfalseuse-seconds是否显示秒booleanfalse以上默认值与 props.ts 中的 prop 定义一致elevation通过formatElevation工具转成 elevation 类名如elevation为true时等价于等级 2见 TimePicker.vue 根节点。TimePicker AllowedTime参数说明类型默认值hours限制可选的hourFunction: hour boolean-minutes限制可选的minuteFunction: minute boolean-seconds限制可选的secondFunction: second boolean-事件事件名说明回调参数change时间变化时触发value: stringchange与update:modelValue在每次取值更新时成对触发update函数内依次call两个监听器测试 timePicker v-model and onChange event 验证了拖表盘的每一格移动都会更新标题时间并调用change。插槽名称说明参数actions自定义操作面板-样式变量以下为组件使用的 CSS 变量可以通过 StyleProvider 组件 进行样式定制。变量声明位于 timePicker.less 的:root块与文档一一对应变量名默认值--time-picker-border-radius4px--time-picker-font-sizevar(--font-size-md)--time-picker-min-width290px--time-picker-title-height105px--time-picker-title-padding16px--time-picker-title-margin-bottom8px--time-picker-title-color#fff--time-picker-title-backgroundvar(--color-primary)--time-picker-title-hint-color#fff--time-picker-title-hint-font-size14px--time-picker-title-hint-min-height21px--time-picker-title-inactive-opacity0.6--time-picker-title-time-font-size50px--time-picker-title-time-margin0 5px--time-picker-title-time-border-radius0--time-picker-title-time-padding0--time-picker-title-time-backgroundtransparent--time-picker-title-time-active-backgroundtransparent--time-picker-title-time-container-justify-contentflex-end--time-picker-title-ampm-button-active-backgroundtransparent--time-picker-title-ampm-margin-left10px--time-picker-title-ampm-border-radius0--time-picker-title-ampm-bordernone--time-picker-title-ampm-button-padding2px--time-picker-clock-left27px--time-picker-clock-right27px--time-picker-clock-top27px--time-picker-clock-bottom27px--time-picker-clock-container-width256px--time-picker-clock-container-height256px--time-picker-clock-container-background#e0e0e0--time-picker-clock-hand-heightcalc(50% - 4px)--time-picker-clock-hand-width2px--time-picker-clock-hand-bottom50%--time-picker-clock-hand-leftcalc(50% - 1px)--time-picker-clock-hand-backgroundvar(--color-primary)--time-picker-clock-hand-border-colorvar(--color-primary)--time-picker-clock-hand-before-width10px--time-picker-clock-hand-before-height10px--time-picker-clock-hand-before-border-width2px--time-picker-clock-hand-after-width4px--time-picker-clock-hand-after-height4px--time-picker-clock-item-height32px--time-picker-clock-item-width32px--time-picker-clock-item-active-backgroundvar(--color-primary)--time-picker-clock-item-active-colorvar(--color-on-primary)--time-picker-clock-item-disable-colorrgba(0, 0, 0, 0.26)--time-picker-clock-item-disable-background#bdbdbd--time-picker-clock-item-text-color#555--time-picker-inner-left36px--time-picker-inner-right36px--time-picker-inner-top36px--time-picker-inner-bottom36px--time-picker-body-background#fff--time-picker-body-height288px--time-picker-actions-padding0 8px 12px 8px其中与主题联动最直接的三个变量是--time-picker-title-background、--time-picker-clock-hand-background/--time-picker-clock-hand-border-color与--time-picker-clock-item-active-background默认均取var(--color-primary)随全局主题变化另外title-color/color属性会以内联样式或指针背景色的形式覆盖这些变量测试 timePicker style and format 验证了title-colorpurple直接作用到.var-time-picker__title的 background 内联样式。小结与延伸阅读TimePicker 的取值链路可概括为modelValue字符串 → 解析为角度 → 表盘刻度与指针渲染 → 触摸/点击产生新角度 → 禁用校验disableHourgetIsDisableMinute/Second→ 回写v-model并触发change。相关源码与测试入口TimePicker.vue状态管理、触摸处理、面板切换clock.vue表盘渲染、禁用小时计算、update 事件props.tsprop 定义与刻度常量utils.ts分钟/秒禁用边界判定timePicker.less全部样式变量声明tests/index.spec.js触摸交互、只读、min/max、AM/PM 切换等回归测试赞分享UI组件前端【免费下载链接】varletA Vue3 component library based on Material Design 2 and 3, supporting mobile and desktop.项目地址https://gitcode.com/gh_mirrors/va/varlet点击查看免费下载相关推荐Varlet TimePicker 时间选择器详解从使用到源码的时钟式时间选择实战指南Varlet TimePicker 时间选择器详解从使用到源码的时钟式时间选择实战指南 Varlet基于 Material Design 2/3 的 VueUI组件前端react-toolbox TimePicker 时间选择器组件实战指南从 API 到时钟拨盘实现原理react toolbox TimePicker 时间选择器组件实战指南从 API 到时钟拨盘实现原理 导读 TimePicker 是 react toolb前端UI组件cube-ui TimePicker 时间选择器完全指南从 API 配置到源码级原理cube ui TimePicker 时间选择器完全指南从 API 配置到源码级原理 TimePicker 是 cube ui 中基于 Picker/Casc前端UI组件移动开发创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑