# DatePicker 日期选择

输入框样式的触发器，点击唤出月历面板。是否带时间选择完全由 `format` 模板决定：纯日期模板选中即回填，带时间占位符的模板则进入「日期 + 时间」模式，需要点「确定」收尾。输出**始终是字符串**，即使传入的是 `Date` 对象。

## 代码演示

### 基础用法

默认 `format` 是 `YYYY-MM-DD`，纯日期模式，点选某天即回填并关闭面板。加 `clearable` 可一键清空。

**演示说明：** 选中值始终是 format 描述的字符串，清空时为 `''`。

```vue
<script setup lang="ts">
import { ref } from 'vue'

const date = ref('')
</script>

<template>
  <div class="m-row-demo--col">
    <MDatePicker v-model="date" format="YYYY-MM-DD" placeholder="请选择日期" clearable />
    <span>选中：{{ date || '未选择' }}</span>
  </div>
</template>
```

### 日期时间模式

`format` 中出现 `H` / `mm` / `ss` 即启用时间选择。此时点选日期不会关闭面板，要再点「确定」。

**演示说明：** 时间面板是「时 : 分 : 秒」三列步进器；输出保留几位由 format 决定。

```vue
<script setup lang="ts">
import { ref } from 'vue'

const toMinute = ref('')
const toSecond = ref('')
</script>

<template>
  <div class="m-row-demo--col">
    <MDatePicker v-model="toMinute" format="YYYY-MM-DD HH:mm" placeholder="精确到分" clearable />
    <MDatePicker v-model="toSecond" format="YYYY-MM-DD HH:mm:ss" placeholder="精确到秒" clearable />
    <span>分：{{ toMinute || '未选择' }} / 秒：{{ toSecond || '未选择' }}</span>
  </div>
</template>
```

### 自定义格式

模板支持 `YYYY` / `MM` / `DD` / `HH` / `mm` / `ss` 六种占位符，分隔符随意，中文前缀也照常渲染。

**演示说明：** 这两条都不含时间占位符，所以仍是纯日期模式。

```vue
<script setup lang="ts">
import { ref } from 'vue'

const slash = ref('')
const chinese = ref('')
</script>

<template>
  <div class="m-row-demo--col">
    <MDatePicker v-model="slash" format="YYYY/MM/DD" placeholder="YYYY/MM/DD" />
    <MDatePicker v-model="chinese" format="YYYY年MM月DD日" placeholder="YYYY年MM月DD日" />
    <span>斜杠：{{ slash || '未选择' }} / 中文：{{ chinese || '未选择' }}</span>
  </div>
</template>
```

### 尺寸与圆角

`size` 三档；`radius` 改触发区圆角，`panelRadius` 改弹出面板圆角，`width` 改触发区宽度。

**演示说明：** 最后一条用 `radius="999px"` 把触发器做成胶囊形。

```vue
<script setup lang="ts">
import { ref } from 'vue'

const small = ref('')
const normal = ref('')
const large = ref('')
const rounded = ref('')
</script>

<template>
  <div class="m-row-demo--col">
    <div class="m-row-demo">
      <MDatePicker v-model="small" size="small" placeholder="小" />
      <MDatePicker v-model="normal" size="default" placeholder="默认" />
      <MDatePicker v-model="large" size="large" placeholder="大" />
    </div>
    <MDatePicker
      v-model="rounded"
      width="240px"
      radius="999px"
      panel-radius="16px"
      placeholder="自定义宽度与圆角" />
  </div>
</template>
```

### 可选范围与禁用

`min` / `max` 限定可选区间，越界日期在面板中置灰；`disabled` 整体禁用。

**演示说明：** `min` / `max` 接受 `Date` 或可解析字符串。

```vue
<script setup lang="ts">
import { ref } from 'vue'

function pad(value: number) {
  return value < 10 ? `0${value}` : String(value)
}
function ymd(date: Date) {
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`
}

const today = new Date()
const min = ymd(today)
const max = ymd(new Date(today.getFullYear(), today.getMonth() + 2, today.getDate()))

const inRange = ref('')
const locked = ref('')
</script>

<template>
  <div class="m-row-demo--col">
    <MDatePicker
      v-model="inRange"
      :min="min"
      :max="max"
      placeholder="今天起两个月内可选"
      clearable />
    <MDatePicker v-model="locked" disabled placeholder="禁用状态" />
    <span>范围内选中：{{ inRange || '未选择' }}</span>
  </div>
</template>
```

## API

### Props

| 属性 | 类型 | 默认值 | 说明 |
| --- | --- | --- | --- |
| `modelValue` | `Date \| string \| null` | `undefined` | 当前值（v-model）：`Date` 或可解析字符串，输出始终为 `format` 格式字符串 |
| `placeholder` | `string` | `undefined` | 占位文本 |
| `format` | `string` | `'YYYY-MM-DD'` | 输出格式模板，同时决定是否启用时间选择 |
| `disabled` | `boolean` | `false` | 是否禁用 |
| `clearable` | `boolean` | `false` | 有值时显示清除按钮 |
| `size` | `'small' \| 'default' \| 'large'` | `'default'` | 尺寸 |
| `min` | `Date \| string` | `undefined` | 可选最小日期 |
| `max` | `Date \| string` | `undefined` | 可选最大日期 |
| `appendToBody` | `boolean` | `true` | 挂载到 body |
| `popupPlacement` | `'top' \| 'bottom'` | `'bottom'` | 弹出方向（空间不足时自动翻转） |
| `width` | `string` | `undefined` | 触发区宽度 |
| `radius` | `string` | `undefined` | 触发区圆角（任意 CSS 长度）；默认 4px |
| `panelRadius` | `string` | `undefined` | 弹出面板圆角（任意 CSS 长度）；默认 4px |
| `name` | `string` | `undefined` | 原生 input name（表单提交） |

### Events

| 事件 | 参数 | 说明 |
| --- | --- | --- |
| `update:modelValue` | `value: string` | 选中值变化（`format` 格式字符串；清空时为 `''`） |
| `change` | `value: string` | 选中值变化 |
| `open` | 无 | 面板打开 |
| `close` | 无 | 面板关闭 |

### Slots

无。

### format 与日期时间模式

是否启用时间选择由 `format` 中的占位符决定，判定正则是 `/H|mm|ss/`，**区分大小写**。

| format 示例 | 模式 | 交互差异 |
| --- | --- | --- |
| `YYYY-MM-DD` | 纯日期 | 点选某天即回填并关闭；底部只有「今天」 |
| `YYYY-MM-DD HH:mm` | 日期时间 | 点选日期不关闭，底部出现「此刻」与「确定」，需点「确定」收尾 |
| `YYYY-MM-DD HH:mm:ss` | 日期时间 | 同上一行，输出保留到秒 |

时间部分由内部的 `TimeSpinner` 渲染，固定是「时 : 分 : 秒」三列步进器（列内可上下微调或直接键入）。最终字符串里保留哪些单位，取决于 `format` 里写了哪些占位符。

## 使用建议

::: tip 输出统一按字符串处理
`modelValue` 可以传 `Date`，但组件回写的永远是字符串。提交前如果要和 `Date` 运算，请自行用同一套格式解析，不要假设拿到的是对象。
:::

::: tip 面板里的年月标签可以点
顶部年月标签点击后进入年 / 月快捷面板，跨年跳转比逐月翻页快得多。
:::

::: warning 小写 mm 是「分」，不是「月」
`MM` 才是月份，`mm` 是分钟。写 `YYYY-mm-DD` 会意外触发时间模式。反过来，如果只想要日期，format 里就不要出现 `H`、`mm`、`ss`，例如 `YYYY年MM月DD日` 是安全的。
:::

::: warning 打开面板会锁定页面滚动
面板打开期间会调用 `lockBodyScroll()` 锁住 body 滚动，关闭后恢复。若在面板未关闭时卸载组件，页面滚动会被锁住，注意生命周期与关闭时机。
:::

## 相关组件

- [DateRangePicker 日期范围](/components/date-range-picker)：需要一次选起止两端的场景。
- [Input 输入框](/components/input)：只需要自由文本输入、不做日期约束时使用。
- [Select 选择器](/components/select)：取值来自固定几项、而非任意日期时使用。
