Vant 4 的 TimePicker 组件专注于移动端时间选择场景,常用来让用户从滚轮列表里挑出小时和分钟,也可以扩展到秒、上午下午等粒度。它不依赖 Moment.js 或 dayjs,自身内部完成数据更新和格式化,但在真实项目里,只把组件引入页面远远不够,还要处理默认值、确认回调、范围约束以及与表单校验的配合。本文围绕这些点展开,先介绍基础引入和属性配置,再分析事件参数和数据处理,最后把最容易卡住的问题单独拿出来说明。

一、基础用法:组件引入与核心属性
在 Vue 3 项目中使用 Vant 4,可以通过全量注册或按需引入的方式加载 TimePicker。全量注册适合原型阶段,按需引入则更适合控制打包体积。下面的代码演示了全量注册的常见配置,使用 app.use(Vant) 后,所有 Vant 组件包括 <van-time-picker> 都可以直接在模板中使用。
import { createApp } from 'vue';
import Vant from 'vant';
import 'vant/lib/index.css';
import App from './App.vue';
const app = createApp(App);
app.use(Vant);
app.mount('#app');
模板中通过 v-model 绑定一个数组变量,数组每一项对应一个选择列。默认情况下,TimePicker 只有小时和分钟两列,所以 v-model 的值需要是长度为 2 的字符串数组,例如 ['12', '30']。如果传入字符串或数字,组件内部会尝试转换,但出现奇怪显示时,优先检查这里的数据类型。
<template>
<van-time-picker
v-model="time"
title="选择时间"
:min-hour="8"
:max-hour="20"
:min-minute="0"
:max-minute="55"
@confirm="onConfirm"
@cancel="onCancel"
/>
</template>
<script setup>
import { ref } from 'vue';
const time = ref(['12', '30']);
function onConfirm({ selectedValues }) {
console.log(selectedValues);
}
function onCancel() {
console.log('已取消');
}
</script>
核心属性方面,title 控制顶部标题,confirm-button-text 和 cancel-button-text 可以修改按钮文案。min-hour、max-hour、min-minute、max-minute 用来限制可滚动范围。如果希望显示秒列,可以给 columns-type 传入 ['hour', 'minute', 'second']。这些属性在移动端表单里非常实用,例如约课系统只允许选择 9 点到 21 点之间的时间,就可以用范围属性直接限制,避免用户滑出无效值。
二、事件回调与时间数据处理
TimePicker 提供 confirm、cancel 和 change 三个主要事件。confirm 在用户点击确认按钮时触发,回调参数是一个对象,包含 selectedValues 和 selectedOptions 两个字段。selectedValues 是当前选中的字符串数组,例如 ['14', '25'];selectedOptions 则包含完整选项对象,可以拿到对应的文本和禁用状态。实际开发中多数场景只需要 selectedValues。
function onConfirm({ selectedValues, selectedOptions }) {
console.log('选中的值', selectedValues);
console.log('选中项详情', selectedOptions);
}
得到数组后,通常需要拼接成后端接口要求的格式。比如用 join(':') 即可得到 14:25 这样的字符串。如果后端需要 Date 对象或时间戳,可以再结合今天的日期做一次组合。下面示例展示了一个常见的格式化逻辑,同时保留取消操作的处理。
function onConfirm({ selectedValues }) {
const timeStr = selectedValues.join(':');
console.log(timeStr); // 输出 14:25
const now = new Date();
now.setHours(Number(selectedValues[0]), Number(selectedValues[1]), 0, 0);
console.log(now.getTime());
}
function onCancel() {
console.log('用户取消了选择');
}
如果 TimePicker 是放在 Popup 弹层里,确认事件里除了格式化数据,还要关闭弹层。这时可以把弹层状态放在父组件,通过 v-model:show 控制,在 onConfirm 中先处理数据再设置 show.value = false。这样可以保证数据回填和弹层关闭的顺序不会错乱。
三、常见疑问与避坑指南
第一个高频问题是指定了默认值却没有生效。排查步骤是先看 v-model 绑定的变量是否为数组,再看数组长度是否与 columns-type 的列数匹配。例如列类型为 ['hour', 'minute', 'second'] 时,必须传入 ['08', '30', '00'],只传两项会出现在某一列上选中值却无法显示的情况。另一个容易忽略的点是每一项必须是字符串,数字类型可能在某些版本下导致高亮定位异常。
import { ref } from 'vue';
// 正确:使用数组,且数组每一项都是字符串
const time = ref(['09', '30']);
// 错误示例:不要写成字符串 '09:30',否则组件无法解析默认值
第二个常见疑问是设置了 min-hour 和 max-hour 后,分钟列是否也会跟着受限。答案是分钟列不会自动跟随小时变化,需要单独设置 min-minute 和 max-minute。如果要求“工作日 9:30 以后可约”,除了设置小时范围,还要在确认回调里做逻辑校验,因为分钟范围是全局的,无法针对不同小时做不同限制。这种场景建议在 onConfirm 中再次判断选中值是否符合业务规则。
样式定制也是被问得比较多的问题。TimePicker 默认高度和选中行样式由 Vant 内部 CSS 控制,直接写 style 往往不生效。可以使用 ::v-deep 或 :deep() 选择器修改内部类,例如调整 .van-picker-column__item--selected 的文字颜色和字号。如果只需要微调高度,可以给组件外层容器设置固定高度,并配合 item-height 属性控制单个选项高度,这样能保持滚动流畅度。
最后一个注意点与 Form 表单配合有关。Vant 的 Field 组件不是必须的,TimePicker 本身没有表单校验能力,通常是弹层确认后把值写回表单变量,再触发校验。建议不要在 change 事件里直接写回最终值,因为滚动过程中会频繁触发,容易造成多余接口请求或校验抖动。正确做法是把 change 仅用于预览,确认时再提交最终结果。
Vant4 TimePicker时间选择器Vue移动端组件修改时间:2026-09-29 15:28:34