Calendar 日期日历

用于日期日历场景的 MoriUI 组件。

导入

import { Calendar } from 'moriui'

示例

概览

单日日期选择。

2026年7月
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Event Date, 2026年7月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 7, 15))
</script>

<template>
  <Calendar v-model="date" locale="zh-CN" class="rounded-lg border" />
</template>

基础

最小化的日历。

2026年7月
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Event Date, 2026年7月
<script setup lang="ts">
  import { Calendar } from 'moriui'
</script>

<template>
  <Calendar locale="zh-CN" class="rounded-lg border" />
</template>

多选

多次日期选择。

2026年7月
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Event Date, 2026年7月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const dates = shallowRef<DateValue[]>([
    new CalendarDate(2026, 7, 10),
    new CalendarDate(2026, 7, 15),
    new CalendarDate(2026, 7, 20)
  ])
</script>

<template>
  <Calendar
    v-model="dates"
    multiple
    locale="zh-CN"
    class="rounded-lg border"
  />
</template>

范围

选择日期区间。

二月 - 三月 2026年
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
23
24
25
26
27
28
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
3
4
5
Event Date, 二月 - 三月 2026年
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const start = new CalendarDate(2026, 1, 12)
  const range: DateValue[] = []
  for (let i = 0; i < 30; i++) {
    range.push(start.add({ days: i }))
  }
  const dates = shallowRef(range)
</script>

<template>
  <Calendar
    v-model="dates"
    multiple
    :number-of-months="2"
    locale="zh-CN"
    class="rounded-lg border"
  />
</template>

预设

快捷预设日期。

2026年2月
26
27
28
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
1
2
3
4
5
6
7
8
Event Date, 2026年2月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate, getLocalTimeZone, today } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 2, 12))
  const placeholder = shallowRef<DateValue>(new CalendarDate(2026, 2, 1))

  const presets = [
    { label: '今天', days: 0 },
    { label: '明天', days: 1 },
    { label: '3 天后', days: 3 },
    { label: '一周后', days: 7 },
    { label: '两周后', days: 14 }
  ]

  function selectPreset(days: number) {
    const d = today(getLocalTimeZone()).add({ days })
    date.value = d
    placeholder.value = d.set({ day: 1 })
  }
</script>

<template>
  <div class="w-fit">
    <Calendar
      v-model="date"
      v-model:placeholder="placeholder"
      fixed-weeks
      locale="zh-CN"
      class="rounded-lg border"
    />
    <div class="flex flex-wrap gap-2 border-t p-3">
      <button
        v-for="preset in presets"
        :key="preset.days"
        class="flex-1 rounded-md border px-3 py-1.5 text-sm hover:bg-accent"
        @click="selectPreset(preset.days)"
      >
        {{ preset.label }}
      </button>
    </div>
  </div>
</template>

时间

日期时间选择。

2026年7月
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Event Date, 2026年7月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { Clock } from '@lucide/vue'
  import { CalendarDate } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 7, 12))
</script>

<template>
  <div class="w-fit">
    <Calendar v-model="date" locale="zh-CN" class="rounded-lg border" />
    <div class="flex items-center gap-4 border-t bg-muted/30 p-3">
      <div class="flex items-center gap-2">
        <label for="time-from" class="text-sm text-muted-foreground">开始</label>
        <div class="flex items-center gap-1 rounded-md border bg-background px-3 py-1.5">
          <input
            id="time-from"
            type="time"
            step="1"
            value="10:30:00"
            class="w-20 border-none bg-transparent text-sm outline-none"
          >
          <Clock class="h-4 w-4 text-muted-foreground" />
        </div>
      </div>
      <div class="flex items-center gap-2">
        <label for="time-to" class="text-sm text-muted-foreground">结束</label>
        <div class="flex items-center gap-1 rounded-md border bg-background px-3 py-1.5">
          <input
            id="time-to"
            type="time"
            step="1"
            value="12:30:00"
            class="w-20 border-none bg-transparent text-sm outline-none"
          >
          <Clock class="h-4 w-4 text-muted-foreground" />
        </div>
      </div>
    </div>
  </div>
</template>

标题

自定义月份标题。

2026年7月
29
30
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
2
Event Date, 2026年7月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 7, 15))
</script>

<template>
  <Calendar v-model="date" locale="zh-CN" class="rounded-lg border">
    <template #heading="{ headingValue }">
      <div class="flex items-center gap-1 text-sm font-medium">
        <span class="text-primary">{{ headingValue }}</span>
      </div>
    </template>
  </Calendar>
</template>

自定义日期

在日期格中展示额外信息。

2026年12月
30
1¥100
2¥100
3¥100
4¥100
5¥100
6¥100
7¥100
8已选
9已选
10已选
11已选
12已选
13已选
14已选
15已选
16已选
17已选
18已选
19¥100
20¥100
21¥100
22¥100
23¥100
24¥100
25¥100
26¥100
27¥100
28¥100
29¥100
30¥100
31¥100
1
2
3
Event Date, 2026年12月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const start = new CalendarDate(2026, 12, 8)
  const range: DateValue[] = []
  for (let i = 0; i < 11; i++) {
    range.push(start.add({ days: i }))
  }
  const dates = shallowRef<DateValue[]>(range)
</script>

<template>
  <Calendar
    v-model="dates"
    multiple
    locale="zh-CN"
    class="rounded-lg border"
  >
    <template #day="{ dayValue, today: isToday, selected, outsideView }">
      <div class="flex flex-col items-center gap-0.5">
        <span>{{ dayValue }}</span>
        <span
          v-if="!outsideView && isToday"
          class="text-[8px] font-medium text-primary"
        >今天</span>
        <span
          v-else-if="!outsideView && selected"
          class="text-[8px] font-medium text-primary-foreground"
        >已选</span>
        <span
          v-else-if="!outsideView"
          class="text-[8px] text-muted-foreground"
        >¥100</span>
      </div>
    </template>
  </Calendar>
</template>

周数

左侧显示周数。

2026年1月
29
30
31
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Event Date, 2026年1月
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 1, 12))
</script>

<template>
  <Calendar v-model="date" locale="zh-CN" class="rounded-lg border" />
</template>

RTL

从右到左的日历布局。

يوليو ٢٠٢٦
٢٨
٢٩
٣٠
١
٢
٣
٤
٥
٦
٧
٨
٩
١٠
١١
١٢
١٣
١٤
١٥
١٦
١٧
١٨
١٩
٢٠
٢١
٢٢
٢٣
٢٤
٢٥
٢٦
٢٧
٢٨
٢٩
٣٠
٣١
١
Event Date, يوليو ٢٠٢٦
<script setup lang="ts">
  import type { DateValue } from 'reka-ui'

  import { shallowRef } from 'vue'
  import { Calendar } from 'moriui'
  import { CalendarDate } from '@internationalized/date'

  const date = shallowRef<DateValue>(new CalendarDate(2026, 7, 15))
</script>

<template>
  <Calendar
    v-model="date"
    dir="rtl"
    locale="ar-SA"
    class="rounded-lg border"
  />
</template>

使用说明

选择模式

Calendar 通过 multiple 属性控制单选或多选;day 插槽可自定义日期格内容。

自定义标题

heading 插槽替换默认月份/年份标题。

自定义日期格

day 插槽接收 dayValue/disabled/today/selected 属性,支持自定义渲染。

RTL

日历网格和方向键遵循 dir。

变体

Calendar 没有视觉变体;multiple 控制多选,通过 Reka UI DateField 管理日期状态。

可访问性

Calendar 复用 Reka UI Calendar 的 grid ARIA、方向键导航。每个日期格有正确标签。

API 参考

属性类型默认值说明
Calendar v-modelDateValue | DateValue[] | nullundefined当前选择的日期。
Calendar multiplebooleanfalse允许多选。
Calendar placeholderDateValue今天日历初始聚焦月份。
Calendar numberOfMonthsnumber1同时显示的月份数量。
Calendar localestring'en'日历的语言区域。