DatePicker
DatePicker是基于 Vant 官方DatePicker做的 Formily 字段封装,保留滚轮日期选择体验,同时补上字段触发区、内置弹层和readPretty展示。
与官方的差异
- 当前封装固定通过
Popup弹层承载,不需要手动维护show - 字段值统一保存为字符串,例如
'2026-03-30' format控制字段展示格式,value-format控制实际写回字段的字符串格式- 关闭弹层时会回滚未确认的临时选择,只有点击确认按钮才会写回字段值
- 作为
PickerGroup默认插槽子组件使用时,会自动切换成内联模式并复用PickerGroup的工具栏
基础使用
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { DatePicker, Form, FormButtonGroup, FormItem, Submit } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
import { maxDate, minDate } from './shared'
const form = createForm({
values: {
appointmentDate: '2026-03-30',
},
})
async function handleSubmit(values: typeof form.values) {
await showDemoResult(values)
}
</script>
<template>
<Form :form="form">
<Field
name="appointmentDate"
title="预约日期"
:decorator="[FormItem, { isLink: true }]"
:component="[DatePicker, { minDate, maxDate }]"
/>
<FormButtonGroup>
<Submit :on-submit="handleSubmit">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>自定义列类型
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { DatePicker, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { maxDate, minDate } from './shared'
const form = createForm({
values: {
billingMonth: '2026-06',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="billingMonth"
title="账单月份"
:decorator="[FormItem, { isLink: true }]"
:component="[
DatePicker,
{
columnsType: ['year', 'month'],
minDate,
maxDate,
},
]"
/>
</div>
</FormProvider>
</template>format 与 value-format
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { formilyComputed } from '@silver-formily/reactive-vue'
import { DatePicker, Form, FormButtonGroup, FormItem, Submit } from '@silver-formily/vant'
import { Field } from '@silver-formily/vue'
import { showDemoResult } from '../shared'
import { maxDate, minDate } from './shared'
const form = createForm({
values: {
appointmentDate: '30/03/2026',
},
})
const currentValue = formilyComputed(() => {
return form.values.appointmentDate as string | undefined
})
async function handleSubmit(values: typeof form.values) {
await showDemoResult(values)
}
</script>
<template>
<Form :form="form">
<div class="demo-panel">
<Field
name="appointmentDate"
title="按 DD/MM/YYYY 提交"
:decorator="[FormItem, { isLink: true }]"
:component="[
DatePicker,
{
format: 'YYYY年MM月DD日',
minDate,
maxDate,
valueFormat: 'DD/MM/YYYY',
},
]"
/>
<div class="demo-value">
当前写回值:{{ currentValue || '暂无' }}
</div>
</div>
<FormButtonGroup>
<Submit :on-submit="handleSubmit">
查看结果
</Submit>
</FormButtonGroup>
</Form>
</template>
<style scoped>
.demo-panel {
display: grid;
gap: 12px;
}
.demo-value {
padding: 0 16px;
color: var(--van-text-color-2);
font-size: 14px;
line-height: 20px;
}
</style>自定义弹出位置
vue
<script setup lang="ts">
import { createForm } from '@formily/core'
import { DatePicker, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { maxDate, minDate } from './shared'
const form = createForm({
values: {
renewalDate: '2026-08-18',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="renewalDate"
title="顶部弹出"
:decorator="[FormItem, { isLink: true }]"
:component="[
DatePicker,
{
position: 'top',
minDate,
maxDate,
},
]"
/>
</div>
</FormProvider>
</template>API
使用约定
- 推荐和
FormItem搭配使用,由FormItem负责标题、箭头和反馈状态 - 默认值类型为
string | null - 内部会先按
value-format解析字段值,再转换成 VantDatePicker需要的滚轮数组 - 如果未显式传
value-format,会按columnsType推导默认格式,例如['year', 'month'] -> 'YYYY-MM' - 如果未显式传
format,字段展示会默认复用value-format readonly/readOnly/disabled都会阻止弹层打开- 当前不支持通过组件
ref调用官方实例方法
封装补充 Props
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
modelValue | string | null | 当前字段值 | - |
format | string | 字段展示格式 | 与 value-format 一致 |
valueFormat | string | 字段值格式,对应模板里的 value-format | YYYY-MM-DD |
placeholder | string | 未选择时的展示文案 | '请选择日期' |
displayFormatter | Function | 自定义字段展示区文案,优先级高于 format | - |
readonly | boolean | 只读态,阻止打开弹层 | false |
disabled | boolean | 禁用态,阻止打开弹层 | false |
官方 DatePicker Props
以下属性会直接透传给 Vant DatePicker:
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
title | string | 顶部标题 | 官方默认值 |
columnsType | Array<'year' | 'month' | 'day'> | 日期列类型 | 官方默认值 |
minDate | Date | 可选最小日期 | 官方默认值 |
maxDate | Date | 可选最大日期 | 官方默认值 |
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 |