DatePicker
简介
MDatePicker 是一个功能强大的日期选择器组件,基于 @internationalized/date 提供国际化日期处理能力。支持单日期、日期范围、多日期选择等多种模式,并提供丰富的日期验证和格式化选项。
基础用法
最基础的日期选择器:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const date = shallowRef(new CalendarDate(2025, 11, 18))
</script>
<template>
<MDatePicker v-model="date" />
</template>
日期范围
通过 range 启用范围选择模式:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import type { DateRange } from 'reka-ui'
const dateRange = shallowRef<DateRange>({
start: new CalendarDate(2025, 11, 1),
end: new CalendarDate(2025, 11, 30)
})
</script>
<template>
<MDatePicker v-model="dateRange" range :number-of-months="2" />
</template>
多日期选择
通过 multiple 启用多选模式:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const dates = shallowRef<CalendarDate[]>([
new CalendarDate(2025, 11, 1),
new CalendarDate(2025, 11, 15),
new CalendarDate(2025, 11, 30)
])
</script>
<template>
<MDatePicker
v-model="dates"
multiple
:button-props="{
label: `已选 ${dates.length} 天`,
class: 'w-full'
}"
/>
</template>
日期限制
限制可选日期范围:
<script setup lang="ts">
import type { CalendarDate } from '@internationalized/date'
const formatter = useDateFormatter()
const futureDate = shallowRef<CalendarDate>()
const pastDate = shallowRef<CalendarDate>()
</script>
<template>
<div class="space-y-4">
<UFormField label="未来日期">
<MDatePicker
v-model="futureDate"
:min-value="formatter.getToday()"
:button-props="{ label: '选择未来日期', class: 'w-full' }"
/>
</UFormField>
<UFormField label="过去日期">
<MDatePicker
v-model="pastDate"
:max-value="formatter.getToday()"
:button-props="{ label: '选择过去日期', class: 'w-full' }"
/>
</UFormField>
</div>
</template>
禁用特定日期
使用 isDateUnavailable 禁用特定日期:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
import type { DateValue } from '@internationalized/date'
const formatter = useDateFormatter()
const date = shallowRef(new CalendarDate(2025, 11, 18))
// 禁用周末
const isDateUnavailable = (date: DateValue) => {
return formatter.isWeekend(date)
}
</script>
<template>
<MDatePicker
v-model="date"
:is-date-unavailable="isDateUnavailable"
:button-props="{ label: '仅工作日', class: 'w-full' }"
/>
</template>
格式化显示
支持多种日期格式输出:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const isoDate = shallowRef(new CalendarDate(2025, 11, 18))
const timestampDate = shallowRef(new CalendarDate(2025, 11, 18))
const customDate = shallowRef(new CalendarDate(2025, 11, 18))
</script>
<template>
<div class="space-y-4">
<UFormField label="ISO 格式">
<MDatePicker v-model="isoDate" label-format="iso" :button-props="{ class: 'w-full' }" />
</UFormField>
<UFormField label="时间戳">
<MDatePicker v-model="timestampDate" label-format="timestamp" :button-props="{ class: 'w-full' }" />
</UFormField>
<UFormField label="自定义">
<MDatePicker
v-model="customDate"
:button-props="{ class: 'w-full' }"
:label-format="(fmt, value) => {
if (!value || !fmt.isDateValue(value)) return '选择日期'
return `${fmt.format(value)} (星期${fmt.getDayOfWeek(value)})`
}"
/>
</UFormField>
</div>
</template>
多月份显示
通过 numberOfMonths 同时显示多个月份的日历:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const date = shallowRef(new CalendarDate(2025, 11, 18))
</script>
<template>
<MDatePicker v-model="date" :number-of-months="3" :button-props="{ label: '显示 3 个月', class: 'w-full' }" />
</template>
自定义按钮
通过 buttonProps 自定义按钮样式:
<script setup lang="ts">
import { CalendarDate } from '@internationalized/date'
const date = shallowRef(new CalendarDate(2025, 11, 18))
</script>
<template>
<MDatePicker
v-model="date"
:button-props="{
label: '选择生日',
color: 'primary',
variant: 'outline',
icon: 'i-lucide-cake',
class: 'w-full'
}"
/>
</template>
API
Props
| Prop | Default | Type |
|---|---|---|
as | 'div' | anyThe element or component this component should render as. |
buttonProps | { label: "选择日期" } | ButtonProps
|
popoverProps | PopoverProps<P> | |
labelFormat | 'formatted' | "iso" | "formatted" | "date" | "timestamp" | "unix" | (formatter: { format: (date: DateValue | null | undefined) => string; formatRange: (start: DateValue | null | undefined, end: DateValue | null | undefined, separator?: string) => string; ... 30 more ...; timeZone: string; }, modelValue: CalendarModelValue<...> | undefined): string |
nextYearIcon | appConfig.ui.icons.chevronDoubleRight | anyThe icon to use for the next year control. |
nextYear | Omit<ButtonProps, LinkPropsKeys>Configure the next year button.
| |
nextMonthIcon | appConfig.ui.icons.chevronRight | anyThe icon to use for the next month control. |
nextMonth | Omit<ButtonProps, LinkPropsKeys>Configure the next month button.
| |
prevYearIcon | appConfig.ui.icons.chevronDoubleLeft | anyThe icon to use for the previous year control. |
prevYear | Omit<ButtonProps, LinkPropsKeys>Configure the prev year button.
| |
prevMonthIcon | appConfig.ui.icons.chevronLeft | anyThe icon to use for the previous month control. |
prevMonth | Omit<ButtonProps, LinkPropsKeys>Configure the prev month button.
| |
color | 'primary' | "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral" |
variant | 'solid' | "solid" | "outline" | "soft" | "subtle" |
size | 'md' | "md" | "xs" | "sm" | "lg" | "xl" |
range | RWhether or not a range of dates can be selected | |
multiple | MWhether or not multiple dates can be selected | |
monthControls | boolean Show month controls | |
yearControls | boolean Show year controls | |
defaultValue | CalendarDefaultValue<R, M> | |
defaultPlaceholder | CalendarDate | CalendarDateTime | ZonedDateTimeThe default placeholder date
| |
placeholder | CalendarDate | CalendarDateTime | ZonedDateTimeThe placeholder date, which is used to determine what month to display when no date is selected. This updates as the user navigates the calendar and can be used to programmatically control the calendar view
| |
allowNonContiguousRanges | boolean When combined with | |
pagedNavigation | boolean This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month | |
preventDeselect | boolean Whether or not to prevent the user from deselecting a date without selecting another date first | |
maximumDays | numberThe maximum number of days that can be selected in a range | |
weekStartsOn | 0 | 1 | 2 | 4 | 5 | 3 | 6The day of the week to start the calendar on | |
weekdayFormat | "narrow" | "short" | "long"The format to use for the weekday strings provided via the weekdays slot prop | |
fixedWeeks | boolean Whether or not to always display 6 weeks in the calendar | |
maxValue | CalendarDate | CalendarDateTime | ZonedDateTimeThe maximum date that can be selected
| |
minValue | CalendarDate | CalendarDateTime | ZonedDateTimeThe minimum date that can be selected
| |
numberOfMonths | numberThe number of months to display at once | |
disabled | boolean Whether or not the calendar is disabled | |
readonly | boolean Whether or not the calendar is readonly | |
initialFocus | boolean If true, the calendar will focus the selected day, today, or the first day of the month depending on what is visible when the calendar is mounted | |
isDateDisabled | (date: DateValue): booleanA function that returns whether or not a date is disabled | |
isDateUnavailable | (date: DateValue): booleanA function that returns whether or not a date is unavailable | |
isDateHighlightable | (date: DateValue): booleanA function that returns whether or not a date is hightable | |
nextPage | (placeholder: DateValue): DateValueA function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component. | |
prevPage | (placeholder: DateValue): DateValueA function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component. | |
disableDaysOutsideCurrentView | boolean Whether or not to disable days outside the current view. | |
fixedDate | "start" | "end"Which part of the range should be fixed | |
locale | 'zh-CN' | string语言区域 |
formatOptions | { dateStyle: "medium" } | Intl.DateTimeFormatOptions日期格式化选项
|
timeZone | string时区标识符,默认使用本地时区 | |
modelValue | CalendarModelValue<R, M> | |
ui | { root?: ClassNameValue; header?: ClassNameValue; body?: ClassNameValue; heading?: ClassNameValue; grid?: ClassNameValue; gridRow?: ClassNameValue; gridWeekDaysRow?: ClassNameValue; gridBody?: ClassNameValue; headCell?: ClassNameValue; cell?: ClassNameValue; cellTrigger?: ClassNameValue; } |
Emits
| Event | Type |
|---|---|
update:modelValue | [date: CalendarModelValue<R, M>] |
update:placeholder | [date: DateValue] & [date: DateValue] |
update:validModelValue | [date: DateRange] |
update:startValue | [date: DateValue | undefined] |
close:prevent | [] |
update:open | [value: boolean] |
update:modelValue | [value: ValueType<R, M>] |
Slots
| Slot | Type |
|---|---|
default | { open: boolean; } |
leading | { ui: { base: (props?: Record<string, any> | undefined) => string; label: (props?: Record<string, any> | undefined) => string; leadingIcon: (props?: Record<string, any> | undefined) => string; leadingAvatar: (props?: Record<string, any> | undefined) => string; leadingAvatarSize: (props?: Record<string, any> | undefined) => string; trailingIcon: (props?: Record<string, any> | undefined) => string; }; } |
trailing | { ui: { base: (props?: Record<string, any> | undefined) => string; label: (props?: Record<string, any> | undefined) => string; leadingIcon: (props?: Record<string, any> | undefined) => string; leadingAvatar: (props?: Record<string, any> | undefined) => string; leadingAvatarSize: (props?: Record<string, any> | undefined) => string; trailingIcon: (props?: Record<string, any> | undefined) => string; }; } |
anchor | SlotProps<P> |
day | { day: DateValue; } |
heading | { value: string; } |
week-day | { day: string; } |