---
title: "DatePicker"
description: "基于国际化标准的日期选择器组件。"
seo_title: "DatePicker"
seo_description: "An internationalized date picker supporting single, range and multiple selection, presets and custom output formats."
canonical_url: "https://nuxt.mhaibaraai.cn/docs/components/date-picker"
---
# DatePicker

> 基于国际化标准的日期选择器组件。

## 简介

`MDatePicker` 是一个国际化日期选择器，基于 `@internationalized/date` 处理时区与本地化。支持单日期、日期范围、多日期选择，并提供按钮触发、可清空、快捷预设等多种交互形态。

> \[\!NOTE\]
> See: https://ui.nuxt.com/docs/components/calendar
> 
> 基于 Nuxt UI 的 Calendar 组件封装

> \[\!NOTE\]
> See: https://react-spectrum.adobe.com/internationalized/date/index.html
> 
> 使用 
> 
> @internationalized/date
> 
>  库进行日期处理，确保时区安全和国际化支持。

## 用法

默认按钮触发器展示当前日期，点击打开日历面板后选择并写入 v-model：

```vue
<script setup lang="ts">
const value = ref("")
</script>

<template>
  <MDatePicker />
</template>
```

### `range` 日期范围

`range` 模式维护 `start` / `end` 两端日期，`numberOfMonths` 可同时展示双月日历：

```vue
<script setup lang="ts">
const value = ref("")
</script>

<template>
  <MDatePicker range :number-of-months="2" />
</template>
```

### `numberOfMonths` 月份数量

`numberOfMonths` 控制弹层内并排展示的月份数量，便于跨月选择：

```vue
<template>
  <MDatePicker :number-of-months="3" />
</template>
```

### `clearable` 可清空

`clearable` 在已有值时显示清除入口，点击后重置且不展开日历：

```vue
<template>
  <MDatePicker clearable />
</template>
```

### `presets` 快捷预设

`presets` 设为 `default` 会按当前模式自动生成「今天」「本周」「本月」等快捷项：

```vue
<template>
  <MDatePicker range presets="default" />
</template>
```

### `multiple` 多日期选择

`multiple` 模式将多个日期保存在数组中，按钮文案可根据已选数量动态展示：

```vue
<template>
  <MDatePicker multiple :button-props='{"label":"选择多个日期","color":"primary"}' />
</template>
```

### `buttonProps` 触发按钮

`buttonProps` 透传给触发按钮，可调整 label、color、variant 与 icon：

```vue
<template>
  <MDatePicker :button-props='{"label":"选择生日","color":"primary","variant":"outline","icon":"i-lucide-cake"}' />
</template>
```

## 示例

### 继承字段上下文

放入 `UFormField` 后继承 `size` 与错误态，触发按钮按表单状态渲染：

```vue
<template>
  <UFormField label="预约日期" size="xs" error="示例错误态">
    <MDatePicker />
  </UFormField>
</template>
```

### 融入`UFieldGroup`

与按钮置于 `UFieldGroup` 时共用尺寸与边框衔接，适合筛选栏中组合快捷操作：

```vue
<template>
  <UFieldGroup size="xs">
    <MDatePicker />
    <UButton icon="i-lucide-calendar-check" color="neutral" variant="subtle" />
  </UFieldGroup>
</template>
```

### 限制可选日期边界

`minValue` 与 `maxValue` 会禁用边界外日期，分别约束只能选择未来或过去日期：

```vue [ComponentsDatePickerValidationExample.vue]
<script setup lang="ts">
import type { CalendarDate } from '#movk/types'

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` 可按业务规则禁用日期（如示例中的周末）：

```vue [ComponentsDatePickerUnavailableExample.vue]
<script setup lang="ts">
import { CalendarDate } from '#movk/composables/useDateFormatter'
import type { DateValue } from '#movk/types'

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>
```

### 自定义触发按钮文案

`labelFormat` 接收格式化工具和当前值，可把日期与星期信息组合为按钮 label：

```vue [ComponentsDatePickerFormatExample.vue]
<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>
```

### 自定义快捷预设

`presets` 传入数组可按业务规则返回日期，每项 `value` 是接收 `formatter` 的函数：

```vue [ComponentsDatePickerPresetsExample.vue]
<script setup lang="ts">
import type { DateValue } from '@movk/nuxt'

const value = shallowRef<DateValue>()
</script>

<template>
  <MDatePicker
    v-model="value"
    placeholder="选择日期"
    :presets="[
      { label: '本周一', value: f => f.getStartOfWeek(f.getToday()) as DateValue },
      { label: '本月初', value: f => f.getStartOfMonth(f.getToday()) as DateValue },
      { label: '本年初', value: f => f.getStartOfYear(f.getToday()) as DateValue }
    ]"
  />
</template>
```

## API

### Props

```ts
/**
 * Props for the MDatePicker component
 */
interface MDatePickerProps {
  id?: string | undefined;
  name?: string | undefined;
  /**
   * @default "\"选择日期\""
   */
  placeholder?: string | undefined;
  buttonProps?: ButtonProps | undefined;
  popoverProps?: PopoverProps<P> | undefined;
  /**
   * @default "\"formatted\""
   */
  labelFormat?: LabelFormat | DatePickerLabelFormatter<R, M> | undefined;
  /**
   * v-model 投影输出格式
   */
  valueFormat?: V | undefined;
  clearable?: boolean | undefined;
  /**
   * 快捷预设
   */
  presets?: "default" | DatePickerPreset<R, M>[] | undefined;
  ui?: (Record<string, C> & { content?: SlotClass; arrow?: SlotClass; wrapper?: SlotClass; presets?: SlotClass; presetButton?: SlotClass; calendar?: SlotClass; clearIcon?: SlotClass; }) | undefined;
  /**
   * 语言区域
   */
  locale?: string | undefined;
  /**
   * 日期格式化选项
   */
  formatOptions?: Intl.DateTimeFormatOptions | undefined;
  /**
   * 时区标识符,默认使用本地时区
   */
  timeZone?: string | undefined;
  /**
   * The element or component this component should render as.
   */
  as?: any;
  /**
   * The type of picker.
   * - `date` renders a day calendar whose heading can switch to a month then year view.
   * - `month` renders a standalone month picker.
   * - `year` renders a standalone year picker.
   */
  type?: CalendarType | undefined;
  /**
   * The icon to use for the next year control.
   */
  nextYearIcon?: any;
  /**
   * Configure the next year button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  nextYear?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the next month control.
   */
  nextMonthIcon?: any;
  /**
   * Configure the next month button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  nextMonth?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the previous year control.
   */
  prevYearIcon?: any;
  /**
   * Configure the prev year button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  prevYear?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * The icon to use for the previous month control.
   */
  prevMonthIcon?: any;
  /**
   * Configure the prev month button.
   * `{ color: 'neutral', variant: 'ghost' }`{lang="ts-type"}
   */
  prevMonth?: Omit<ButtonProps, LinkPropsKeys> | undefined;
  /**
   * Whether to make the heading a button that switches between the day, month and year views.
   * Has no effect when `type` is `year`. Can be an object to override the button props.
   * `{ color: 'neutral', variant: 'ghost', block: true }`{lang="ts-type"}
   */
  viewControl?: boolean | Omit<ButtonProps, LinkPropsKeys> | undefined;
  color?: "primary" | "secondary" | "info" | "success" | "warning" | "error" | "important" | "neutral" | undefined;
  variant?: "solid" | "outline" | "soft" | "subtle" | undefined;
  size?: "xs" | "sm" | "md" | "lg" | "xl" | undefined;
  /**
   * Whether or not a range of dates can be selected
   */
  range?: R | undefined;
  /**
   * Whether or not multiple dates can be selected
   */
  multiple?: M | undefined;
  /**
   * Show month controls
   */
  monthControls?: boolean | undefined;
  /**
   * Show year controls
   */
  yearControls?: boolean | undefined;
  defaultValue?: CalendarDefaultValue<R, M> | undefined;
  weekNumbers?: boolean | undefined;
  /**
   * The default placeholder date
   */
  defaultPlaceholder?: DateValue | undefined;
  /**
   * When combined with `isDateUnavailable`, determines whether non-contiguous ranges, i.e. ranges containing unavailable dates, may be selected.
   */
  allowNonContiguousRanges?: boolean | undefined;
  /**
   * This property causes the previous and next buttons to navigate by the number of months displayed at once, rather than one month
   */
  pagedNavigation?: boolean | undefined;
  /**
   * Whether or not to prevent the user from deselecting a date without selecting another date first
   */
  preventDeselect?: boolean | undefined;
  /**
   * The maximum number of days that can be selected in a range
   */
  maximumDays?: number | undefined;
  /**
   * The day of the week to start the calendar on
   */
  weekStartsOn?: WeekStartsOn | undefined;
  /**
   * The format to use for the weekday strings provided via the weekdays slot prop
   */
  weekdayFormat?: WeekDayFormat | undefined;
  /**
   * Whether or not to always display 6 weeks in the calendar
   */
  fixedWeeks?: boolean | undefined;
  /**
   * The maximum date that can be selected
   */
  maxValue?: DateValue | undefined;
  /**
   * The minimum date that can be selected
   */
  minValue?: DateValue | undefined;
  /**
   * The number of months to display at once
   */
  numberOfMonths?: number | undefined;
  /**
   * Whether or not the calendar is disabled
   */
  disabled?: boolean | undefined;
  /**
   * Whether or not the calendar is readonly
   */
  readonly?: boolean | undefined;
  /**
   * 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
   */
  initialFocus?: boolean | undefined;
  /**
   * A function that returns whether or not a date is disabled
   */
  isDateDisabled?: Matcher | undefined;
  /**
   * A function that returns whether or not a date is unavailable
   */
  isDateUnavailable?: Matcher | undefined;
  /**
   * A function that returns whether or not a date is hightable
   */
  isDateHighlightable?: Matcher | undefined;
  /**
   * A function that returns the next page of the calendar. It receives the current placeholder as an argument inside the component.
   */
  nextPage?: ((placeholder: DateValue) => DateValue) | undefined;
  /**
   * A function that returns the previous page of the calendar. It receives the current placeholder as an argument inside the component.
   */
  prevPage?: ((placeholder: DateValue) => DateValue) | undefined;
  /**
   * Whether or not to disable days outside the current view.
   */
  disableDaysOutsideCurrentView?: boolean | undefined;
  /**
   * Which part of the range should be fixed
   */
  fixedDate?: "start" | "end" | undefined;
  /**
   * A function that returns whether or not a month is disabled
   */
  isMonthDisabled?: Matcher | undefined;
  /**
   * A function that returns whether or not a month is unavailable
   */
  isMonthUnavailable?: Matcher | undefined;
  /**
   * A function that returns whether or not a year is disabled
   */
  isYearDisabled?: Matcher | undefined;
  /**
   * A function that returns whether or not a year is unavailable
   */
  isYearUnavailable?: Matcher | undefined;
  modelValue?: FormattedValue<R, M, V> | undefined;
}
```

### Emits

```ts
/**
 * Emitted events for the MDatePicker component
 */
interface MDatePickerEmits {
  update:modelValue: (payload: [value: FormattedValue<R, M, V>]) => void;
  update:placeholder: (payload: [date: DateValue]) => void;
  update:validModelValue: (payload: [date: DateRange]) => void;
  update:startValue: (payload: [date: DateValue | undefined]) => void;
  close:prevent: (payload: []) => void;
  update:open: (payload: [value: boolean]) => void;
  update:modelValue: (payload: [value: FormattedValue<R, M, V> | undefined]) => void;
}
```

### Slots

```ts
/**
 * Slots for the MDatePicker component
 */
interface MDatePickerSlots {
  default(): any;
  content(): any;
  heading(): any;
  day(): any;
  week-day(): any;
  month-cell(): any;
  year-cell(): any;
  leading(): any;
  trailing(): any;
}
```

## Theme

<component-theme></component-theme>## Changelog

See commit history for [src/runtime/components/DatePicker.vue](https://github.com/mhaibaraai/movk-nuxt/commits/main/src/runtime/components/DatePicker.vue).


## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
