Calendar
提示
- 传入与传出的值均经过dayjs转换,变为string。
- 由于 Calendar 组件内置了
poppable属性,本组件没有通过createPopup进行封装。
选择切换模式
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { juneEnd, marchStart } from './shared'
const form = createForm({
values: {
scheduleDate: '2026-06-18',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="scheduleDate"
title="选择切换模式"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
switchMode: 'year-month',
minDate: marchStart,
maxDate: juneEnd,
},
]"
/>
</div>
</FormProvider>
</template>选择单个日期 / 多个日期 / 日期区间
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
singleDate: '2026-03-23',
multipleDates: [
'2026-03-05',
'2026-03-12',
'2026-03-19',
],
tripRange: ['2026-03-24', '2026-03-28'],
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="singleDate"
title="选择单个日期"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
minDate: marchStart,
maxDate: aprilEnd,
},
]"
/>
<Field
name="multipleDates"
title="选择多个日期"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'multiple',
minDate: marchStart,
maxDate: aprilEnd,
},
]"
/>
<Field
name="tripRange"
title="选择日期区间"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'range',
minDate: marchStart,
maxDate: aprilEnd,
},
]"
/>
</div>
</FormProvider>
</template>快捷选择
vue
<script setup lang="ts">
import type { CalendarModelValue } from '@silver-formily/vant'
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { showToast } from 'vant'
import { aprilEnd, formatModelValue, marchStart } from './shared'
const form = createForm({
values: {
expressDate: null,
},
})
function onConfirm(value: CalendarModelValue) {
showToast(`已确认:${formatModelValue(value)}`)
}
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="expressDate"
title="快捷选择"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
minDate: marchStart,
maxDate: aprilEnd,
showConfirm: false,
placeholder: '选择后会立即确认',
onConfirm,
},
]"
/>
</div>
</FormProvider>
</template>自定义颜色
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
specialDate: '2026-04-08',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="specialDate"
title="自定义颜色"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
color: '#ee0a24',
minDate: marchStart,
maxDate: aprilEnd,
},
]"
/>
</div>
</FormProvider>
</template>自定义日期范围
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { marchCustomMax, marchCustomMin } from './shared'
const form = createForm({
values: {
limitedDate: '2026-03-15',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="limitedDate"
title="自定义日期范围"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
minDate: marchCustomMin,
maxDate: marchCustomMax,
placeholder: '仅可选择 03-10 至 03-20',
},
]"
/>
</div>
</FormProvider>
</template>自定义按钮文字
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
stayRange: null,
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="stayRange"
title="自定义按钮文字"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'range',
minDate: marchStart,
maxDate: aprilEnd,
confirmText: '完成',
confirmDisabledText: '请选择结束时间',
},
]"
/>
</div>
</FormProvider>
</template>自定义日期文案
vue
<script setup lang="ts">
import type { CalendarDayItem } from '@silver-formily/vant'
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { mayEnd, mayStart } from './shared'
const form = createForm({
values: {
holidayRange: ['2026-05-01', '2026-05-04'],
},
})
function formatter(day: CalendarDayItem) {
const month = day.date.getMonth() + 1
const date = day.date.getDate()
if (month === 5) {
if (date === 1) {
day.topInfo = '劳动节'
}
else if (date === 4) {
day.topInfo = '青年节'
}
else if (date === 11) {
day.text = '今天'
}
}
if (day.type === 'start') {
day.bottomInfo = '入住'
}
else if (day.type === 'end') {
day.bottomInfo = '离店'
}
return day
}
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="holidayRange"
title="自定义日期文案"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'range',
minDate: mayStart,
maxDate: mayEnd,
formatter,
},
]"
/>
</div>
</FormProvider>
</template>自定义插槽
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { mayEnd, mayStart } from './shared'
const form = createForm({
values: {
tripRange: ['2026-05-18', '2026-05-21'],
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="tripRange"
title="自定义插槽"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'range',
minDate: mayStart,
maxDate: mayEnd,
},
]"
>
<template #title>
<div class="calendar-slot-title">
行程日历
</div>
</template>
<template #bottom-info="day">
<span
v-if="day.date?.getDate?.() === 18"
class="calendar-slot-tip"
>
出发
</span>
<span
v-else-if="day.date?.getDate?.() === 21"
class="calendar-slot-tip"
>
返程
</span>
</template>
<template #footer>
<div class="calendar-slot-footer">
已透传官方插槽,可在这里放业务说明或快捷提示
</div>
</template>
</Field>
</div>
</FormProvider>
</template>
<style scoped>
.calendar-slot-title {
padding: 8px 0;
font-size: 16px;
font-weight: 600;
letter-spacing: 0.04em;
}
.calendar-slot-tip {
font-size: 10px;
color: var(--van-primary-color);
}
.calendar-slot-footer {
padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
font-size: 12px;
line-height: 1.5;
color: var(--van-text-color-2);
background: linear-gradient(180deg, rgba(250, 250, 250, 0) 0%, rgba(247, 248, 250, 1) 100%);
}
</style>自定义弹出位置
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
asideDate: '2026-03-27',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="asideDate"
title="自定义弹出位置"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
position: 'right',
round: false,
minDate: marchStart,
maxDate: aprilEnd,
},
]"
/>
</div>
</FormProvider>
</template>日期区间最大范围
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
shortTrip: null,
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="shortTrip"
title="日期区间最大范围"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
type: 'range',
minDate: marchStart,
maxDate: aprilEnd,
maxRange: 3,
rangePrompt: '最多选择 3 天',
},
]"
/>
</div>
</FormProvider>
</template>自定义周起始日
vue
<script setup lang="ts">
import { createForm } from '@silver-formily/core'
import { Calendar, FormItem } from '@silver-formily/vant'
import { Field, FormProvider } from '@silver-formily/vue'
import { aprilEnd, marchStart } from './shared'
const form = createForm({
values: {
mondayFirstDate: '2026-03-23',
},
})
</script>
<template>
<FormProvider :form="form">
<div class="demo-panel">
<Field
name="mondayFirstDate"
title="自定义周起始日"
:decorator="[FormItem, { isLink: true }]"
:component="[
Calendar,
{
minDate: marchStart,
maxDate: aprilEnd,
firstDayOfWeek: 1,
},
]"
/>
</div>
</FormProvider>
</template>平铺展示
官方文档里还有一个依赖 poppable=false 的“平铺展示”示例,但当前封装固定为弹层模式,因此这里不提供对应 demo。
API
使用约定
- 触发区交互状态跟随
Field的disabled/readOnly/readPretty,不会透传到内部 VantCalendar
封装补充 Props
| 属性名 | 类型 | 描述 | 默认值 |
|---|---|---|---|
modelValue | string | string[] | null | 当前选中值 | - |
format | string | 字段展示区日期格式 | YYYY-MM-DD |
valueFormat | string | 绑定值日期格式 | YYYY-MM-DD |
placeholder | string | 未选择时的展示文案 | 单选为“请选择日期”,区间为“请选择日期范围” |
displayFormatter | Function | 自定义字段展示区文案 | - |
Props
除了 maxDate minDate 改为字符串格式入参之外,其余的Props与插槽均可直接参考Vant 官方文档页
Events
| 事件名 | 描述 | 回调参数 |
|---|---|---|
update:modelValue | 点击确认后同步字段值 | Function |
select | 选中任意日期时触发 | Function |
confirm | 日期选择完成后触发 | Function |
open | 弹层打开时触发 | - |
close | 弹层关闭时触发 | - |
opened | 弹层打开且动画结束后触发 | - |
closed | 弹层关闭且动画结束后触发 | - |
unselect | 多选模式取消选中时触发 | Function |
monthShow | 月份进入可视区域时触发 | Function |
overRange | 超出最大范围时触发 | - |
clickSubtitle | 点击副标题时触发 | Function |
clickDisabledDate | 点击禁用日期时触发 | Function |
clickOverlay | 点击遮罩层时触发 | Function |
panelChange | 面板切换时触发 | Function |
update:show | 弹层开关变化时触发 | Function |