TimePicker
TimePicker是基于 Vant 官方TimePicker做的 Formily 字段封装,保留滚轮时间选择体验,同时补上字段触发区、内置弹层和readPretty展示。
与官方的差异
- 当前封装固定通过
Popup弹层承载,不需要手动维护show - 字段值统一保存为字符串,例如
'09:30'、'09:30:15' format控制字段展示格式,value-format控制实际写回字段的字符串格式- 关闭弹层时会回滚未确认的临时选择,只有点击确认按钮才会写回字段值
- 作为
PickerGroup默认插槽子组件使用时,会自动切换成内联模式并复用PickerGroup的工具栏
基础用法
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:00',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="当前时间"
:decorator="[FormItem, { isLink: true }]"
:component="[TimePicker]"
/>
</div>
</FormProvider>
</template>选项类型
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:00:00',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="选择时分秒"
:decorator="[FormItem, { isLink: true }]"
:component="[
TimePicker,
{
columnsType: ['hour', 'minute', 'second'],
},
]"
/>
</div>
</FormProvider>
</template>时间范围
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:35',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="限制小时与分钟范围"
:decorator="[FormItem, { isLink: true }]"
:component="[
TimePicker,
{
minHour: 10,
maxHour: 20,
minMinute: 30,
maxMinute: 40,
},
]"
/>
</div>
</FormProvider>
</template>整体时间范围
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:00:00',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="限制整体时间范围"
:decorator="[FormItem, { isLink: true }]"
:component="[
TimePicker,
{
columnsType: ['hour', 'minute', 'second'],
minTime: '09:40:10',
maxTime: '20:20:50',
},
]"
/>
</div>
</FormProvider>
</template>格式化选项
vue
<script setup lang="ts">
import type { PickerOption } from '@silver-formily/vant'
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:00:00',
},
})
function formatter(type: string, option: PickerOption) {
if (type === 'hour') {
option.text += '时'
}
if (type === 'minute') {
option.text += '分'
}
if (type === 'second') {
option.text += '秒'
}
return option
}
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="格式化时间选项"
:decorator="[FormItem, { isLink: true }]"
:component="[
TimePicker,
{
columnsType: ['hour', 'minute', 'second'],
formatter,
},
]"
/>
</div>
</FormProvider>
</template>过滤选项
vue
<script setup lang="ts">
import type { PickerOption } from '@silver-formily/vant'
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '12:00',
},
})
function filter(type: string, options: PickerOption[]) {
if (type === 'minute') {
return options.filter(option => Number(option.value) % 10 === 0)
}
return options
}
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="按 10 分钟间隔选择"
:decorator="[FormItem, { isLink: true }]"
:component="[TimePicker, { filter }]"
/>
</div>
</FormProvider>
</template>高级用法
vue
<script setup lang="ts">
import type { PickerOption } from '@silver-formily/vant'
import { createForm } from '@formily/core'
import { FormItem, TimePicker } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
const form = createForm({
values: {
currentTime: '08:40',
},
})
function filter(type: string, options: PickerOption[], values: string[]) {
const hour = Number(values[0])
if (type === 'hour') {
return options.filter((option) => {
const value = Number(option.value)
return value >= 8 && value <= 18
})
}
if (type === 'minute') {
const minuteOptions = options.filter(option => Number(option.value) % 10 === 0)
if (hour === 8) {
return minuteOptions.filter(option => Number(option.value) >= 40)
}
if (hour === 18) {
return minuteOptions.filter(option => Number(option.value) <= 20)
}
return minuteOptions
}
return options
}
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="currentTime"
title="营业时间段内选择"
:decorator="[FormItem, { isLink: true }]"
:component="[TimePicker, { filter }]"
/>
</div>
</FormProvider>
</template>API
使用约定
- 推荐和
FormItem搭配使用,由FormItem负责标题、箭头和反馈状态 - 默认值类型为
string | null - 内部会先按
value-format解析字段值,再转换成 VantTimePicker需要的滚轮数组 - 如果未显式传
value-format,会按columnsType推导默认格式,例如['hour', 'minute'] -> 'HH:mm' - 如果未显式传
format,字段展示会默认复用value-format minTime/maxTime仍遵循官方格式,固定使用HH:mm:ssreadonly/readOnly/disabled都会阻止弹层打开- 当前不支持通过组件
ref调用官方实例方法
封装补充 Props
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
modelValue | string | null | 当前字段值 | - |
format | string | 字段展示格式 | 与 value-format 一致 |
valueFormat | string | 字段值格式,对应模板里的 value-format | HH:mm |
placeholder | string | 未选择时的展示文案 | '请选择时间' |
displayFormatter | Function | 自定义字段展示区文案,优先级高于 format | - |
readonly | boolean | 只读态,阻止打开弹层 | false |
disabled | boolean | 禁用态,阻止打开弹层 | false |
separator | string | 默认格式推导时使用的分隔符 | ':' |
官方 TimePicker Props
以下属性会直接透传给 Vant TimePicker:
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
title | string | 顶部标题 | 官方默认值 |
columnsType | Array<'hour' | 'minute' | 'second'> | 时间列类型 | 官方默认值 |
minHour | number | string | 可选最小小时 | 官方默认值 |
maxHour | number | string | 可选最大小时 | 官方默认值 |
minMinute | number | string | 可选最小分钟 | 官方默认值 |
maxMinute | number | string | 可选最大分钟 | 官方默认值 |
minSecond | number | string | 可选最小秒数 | 官方默认值 |
maxSecond | number | string | 可选最大秒数 | 官方默认值 |
minTime | string | 最小可选时间 | 官方默认值 |
maxTime | string | 最大可选时间 | 官方默认值 |
cancelButtonText | string | 取消按钮文案 | 官方默认值 |
confirmButtonText | string | 确认按钮文案 | 官方默认值 |
loading | boolean | 是否显示加载状态 | 官方默认值 |
optionHeight | number | string | 选项高度 | 官方默认值 |
visibleOptionNum | number | string | 可见选项个数 | 官方默认值 |
swipeDuration | number | string | 滚动惯性动画时长 | 官方默认值 |
allowHtml | boolean | 是否渲染 HTML 文案 | 官方默认值 |
formatter | Function | 自定义选项展示 | 官方默认值 |
filter | Function | 自定义选项过滤 | 官方默认值 |
官方 Popup Props
当前封装内部固定包了一层 Popup,以下弹层属性可直接使用:
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
position | enum | 弹出位置 | 'bottom' |
round | boolean | 是否显示圆角 | true |
overlay | boolean | 是否显示遮罩层 | true |
teleport | string | Element | 指定挂载节点 | 官方默认值 |
closeOnPopstate | boolean | 回退时是否自动关闭 | true |
closeOnClickOverlay | boolean | 点击遮罩是否自动关闭 | true |
safeAreaInsetTop | boolean | 是否开启顶部安全区 | 官方默认值 |
safeAreaInsetBottom | boolean | 是否开启底部安全区 | true |
lockScroll | boolean | 是否锁定背景滚动 | true |
lazyRender | boolean | 是否延迟渲染内容 | true |
zIndex | number | string | 弹层层级 | 官方默认值 |
duration | number | string | 动画时长 | 官方默认值 |
transition | string | 自定义过渡动画 | 官方默认值 |
Slots
以下官方插槽已转发:
| 插槽名 | 描述 | 插槽参数 |
|---|---|---|
title | 自定义标题 | - |
cancel | 自定义取消按钮 | - |
confirm | 自定义确认按钮 | - |
toolbar | 自定义整个工具栏 | - |
option | 自定义选项内容 | option |
columns-top | 选项区顶部内容 | - |
columns-bottom | 选项区底部内容 | - |
Events
| 事件名 | 描述 | 回调参数 |
|---|---|---|
update:modelValue | 点击确认后同步字段值 | Function |
change | 任意列发生切换时触发 | Function |
confirm | 点击确认按钮时触发 | Function |
cancel | 点击取消按钮时触发 | Function |
open | 弹层打开时触发 | - |
close | 弹层关闭时触发 | - |
opened | 弹层打开且动画结束后触发 | - |
closed | 弹层关闭且动画结束后触发 | - |
clickOverlay | 点击遮罩层时触发 | Function |
update:show | 弹层开关变化时触发 | Function |