DatePicker

View source
基于国际化标准的日期选择器组件

简介

MDatePicker 是一个功能强大的日期选择器组件,基于 @internationalized/date 提供国际化日期处理能力。支持单日期、日期范围、多日期选择等多种模式,并提供丰富的日期验证和格式化选项。

基于 Nuxt UI 的 Calendar 组件封装
使用 @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'any

The 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
nextYearIconappConfig.ui.icons.chevronDoubleRightany

The icon to use for the next year control.

nextYear Omit<ButtonProps, LinkPropsKeys>

Configure the next year button. { color: 'neutral', variant: 'ghost' }

nextMonthIconappConfig.ui.icons.chevronRightany

The icon to use for the next month control.

nextMonth Omit<ButtonProps, LinkPropsKeys>

Configure the next month button. { color: 'neutral', variant: 'ghost' }

prevYearIconappConfig.ui.icons.chevronDoubleLeftany

The icon to use for the previous year control.

prevYear Omit<ButtonProps, LinkPropsKeys>

Configure the prev year button. { color: 'neutral', variant: 'ghost' }

prevMonthIconappConfig.ui.icons.chevronLeftany

The icon to use for the previous month control.

prevMonth Omit<ButtonProps, LinkPropsKeys>

Configure the prev month button. { color: 'neutral', variant: 'ghost' }

color'primary' "primary" | "secondary" | "success" | "info" | "warning" | "error" | "neutral"
variant'solid' "solid" | "outline" | "soft" | "subtle"
size'md' "md" | "xs" | "sm" | "lg" | "xl"
range R

Whether or not a range of dates can be selected

multiple M

Whether or not multiple dates can be selected

monthControlsboolean

Show month controls

yearControlsboolean

Show year controls

defaultValue CalendarDefaultValue<R, M>
defaultPlaceholder CalendarDate | CalendarDateTime | ZonedDateTime

The default placeholder date

placeholder CalendarDate | CalendarDateTime | ZonedDateTime

The 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

allowNonContiguousRangesboolean

When combined with isDateUnavailable, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected.

pagedNavigationboolean

This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month

preventDeselectboolean

Whether or not to prevent the user from deselecting a date without selecting another date first

maximumDays number

The maximum number of days that can be selected in a range

weekStartsOn 0 | 1 | 2 | 4 | 5 | 3 | 6

The 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

fixedWeeksboolean

Whether or not to always display 6 weeks in the calendar

maxValue CalendarDate | CalendarDateTime | ZonedDateTime

The maximum date that can be selected

minValue CalendarDate | CalendarDateTime | ZonedDateTime

The minimum date that can be selected

numberOfMonths number

The number of months to display at once

disabledboolean

Whether or not the calendar is disabled

readonlyboolean

Whether or not the calendar is readonly

initialFocusboolean

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): boolean

A function that returns whether or not a date is disabled

isDateUnavailable (date: DateValue): boolean

A function that returns whether or not a date is unavailable

isDateHighlightable (date: DateValue): boolean

A function that returns whether or not a date is hightable

nextPage (placeholder: DateValue): DateValue

A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component.

prevPage (placeholder: DateValue): DateValue

A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component.

disableDaysOutsideCurrentViewboolean

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; }; }
anchorSlotProps<P>
day{ day: DateValue; }
heading{ value: string; }
week-day{ day: string; }

Changelog

d4a6c — refactor: 将组件 Props 类型定义提取到独立文件

9bdda — refactor: 优化组件代码格式

c527c — ✨ feat: 增强 AutoForm 支持标签输入控件和日期数组字段

1cf3c — 📚 docs: 恢复 AutoForm 示例页面完整功能并添加新控件

Copyright © 2025 - 2026 YiXuan - MIT License