Skip to content

日历 Calendar ​

赞助

按照日历形式展示数据的容器

何时使用 ​

  • 当数据是日期或按照日期划分时,例如日程、课表、价格日历等;目前支持年/月切换

参考文档 ​

基本使用 ​

2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
const date = ref(Date.now())
watchEffect(() => {
  console.log('date', date.value)
})
function onChange(
  date: string | number,
  dateOrMonth: CalendarDateItem['dateObject'] | CalendarMonthItem['monthObject']
) {
  console.log('change', date, dateOrMonth)
}
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Calendar v-model:value="date" @change="onChange" @panelChange="onPanelChange" />
</template>

卡片模式 ​

2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
const cardDate = ref(Date.now())
watchEffect(() => {
  console.log('cardDate', cardDate.value)
})
function onChange(
  date: string | number,
  dateOrMonth: CalendarDateItem['dateObject'] | CalendarMonthItem['monthObject']
) {
  console.log('change', date, dateOrMonth)
}
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Calendar v-model:value="cardDate" display="card" @change="onChange" @panelChange="onPanelChange" />
</template>

初始模式 ​

display:
panel
card
2026年
2026年
月
年
1月
2月
3月
4月
5月
6月
7月
8月
9月
10月
11月
12月
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
const modeDate = ref(Date.now())
const displayOptions = [
  {
    label: 'panel',
    value: 'panel'
  },
  {
    label: 'card',
    value: 'card'
  }
]
const modeDisplay = ref('card')
watchEffect(() => {
  console.log('modeDate', modeDate.value)
})
</script>
<template>
  <Flex vertical>
    <Space align="center">
      display:<Radio :options="displayOptions" v-model:value="modeDisplay" button button-style="solid" />
    </Space>
    <Calendar v-model:value="modeDate" mode="year" :display="modeDisplay" />
  </Flex>
</template>

自定义头部内容 ​

Custom header
2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
日历
2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { CalendarOutlined } from '@ant-design/icons-vue'
const headerDate = ref(Date.now())
watchEffect(() => {
  console.log('headerDate', headerDate.value)
})
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Space>
    <Calendar v-model:value="headerDate" header="Custom header" display="card" @panelChange="onPanelChange" />
    <Calendar v-model:value="headerDate" display="card" @panelChange="onPanelChange">
      <template #header> <CalendarOutlined /> 日历 </template>
    </Calendar>
  </Space>
</template>

自定义一周的开始 ​

startDayOfWeek:
周一
周二
周三
周四
周五
周六
周日
2026年
2026年
10月
10月
月
年
日一二三四五六
27
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import type { CalendarDayOfWeek } from 'vue-amazing-ui'
const startDayOfWeekDate = ref(Date.now())
const weekOptions = [
  {
    label: '周一',
    value: 0
  },
  {
    label: '周二',
    value: 1
  },
  {
    label: '周三',
    value: 2
  },
  {
    label: '周四',
    value: 3
  },
  {
    label: '周五',
    value: 4
  },
  {
    label: '周六',
    value: 5
  },
  {
    label: '周日',
    value: 6
  }
]
const startDayOfWeek = ref<CalendarDayOfWeek>(6)
watchEffect(() => {
  console.log('startDayOfWeekDate', startDayOfWeekDate.value)
})
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Flex vertical>
    <Space align="center">
      startDayOfWeek:<Radio :options="weekOptions" v-model:value="startDayOfWeek" button button-style="solid" />
    </Space>
    <Calendar v-model:value="startDayOfWeekDate" :start-day-of-week="startDayOfWeek" @panelChange="onPanelChange" />
  </Flex>
</template>

自定义展示格式 ​

使用 weekFormat / dateFormat / monthFormat 自定义日期/星期/月的展示格式


Date format
2026年
2026年
10月
10月
月
年
一二三四五六日
28
29
30
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
01
Week format
2026年
2026年
10月
10月
月
年
周一周二周三周四周五周六周日
28
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
Month format
2026年
2026年
月
年
一月
二月
三月
四月
五月
六月
七月
八月
九月
十月
十一月
十二月
2026年
2026年
10月
10月
月
年
MondayTuesdayWednesdayThursdayFridaySaturdaySunday
28th
29th
30th
1st
2nd
3rd
4th
5th
6th
7th
8th
9th
10th
11th
12th
13th
14th
15th
16th
17th
18th
19th
20th
21st
22nd
23rd
24th
25th
26th
27th
28th
29th
30th
31st
1st
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format } from 'date-fns'
const formatDate = ref(Date.now())
watchEffect(() => {
  console.log('formatDate', formatDate.value)
})
function cardDateFormat(date: number, timestamp: number) {
  return String(date).padStart(2, '0')
}
function cardWeekFormat(defaultWeek: CalendarDefaultWeek, week: CalendarDayOfWeek) {
  return `周${defaultWeek}`
}
function cardMonthFormat(month: number, timestamp: number) {
  const chineseNumber = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二']
  return `${chineseNumber[month - 1]}月`
}
function panelDateFormat(date: number, timestamp: number) {
  return format(timestamp, 'do')
}
function panelWeekFormat(defaultWeek: CalendarDefaultWeek, week: CalendarDayOfWeek, timestamp: number) {
  return format(timestamp, 'EEEE')
}
function panelMonthFormat(month: number, timestamp: number) {
  return format(timestamp, 'MMM')
}
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Flex vertical>
    <Space>
      <Calendar
        header="Date format"
        display="card"
        v-model:value="formatDate"
        :date-format="cardDateFormat"
        @panelChange="onPanelChange"
      />
      <Calendar
        header="Week format"
        display="card"
        v-model:value="formatDate"
        :week-format="cardWeekFormat"
        @panelChange="onPanelChange"
      />
      <Calendar
        header="Month format"
        mode="year"
        display="card"
        v-model:value="formatDate"
        :month-format="cardMonthFormat"
        @panelChange="onPanelChange"
      />
    </Space>
    <Calendar
      v-model:value="formatDate"
      :date-format="panelDateFormat"
      :week-format="panelWeekFormat"
      :month-format="panelMonthFormat"
      @panelChange="onPanelChange"
    />
  </Flex>
</template>

通知事项日历 ​

2026年
2026年
10月
10月
月
年
一二三四五六日
28
29
30
1
2
3
4
5
6
7
8日
This is warning event.
This is usual event.
This is volcano event
9
10
11
12日
This is warning event.
This is usual event.
This is volcano event
13
14
15
16日
This is warning event.
This is usual event.
This is volcano event
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
1
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
const noticeDate = ref(Date.now())
watchEffect(() => {
  console.log('noticeDate', noticeDate.value)
})
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Calendar v-model:value="noticeDate" @panelChange="onPanelChange">
    <template #dateValue="{ dateObject, timestamp }">
      <span v-if="[8, 12, 16].includes(dateObject.date)">{{ dateObject.date }}日</span>
    </template>
    <template #dateContent="{ dateObject, timestamp }">
      <template v-if="[8, 12, 16].includes(dateObject.date)">
        <div class="notice-item">
          <Badge status="warning" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is warning event.</Ellipsis>
        </div>
        <div class="notice-item">
          <Badge status="success" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is usual event.</Ellipsis>
        </div>
        <div class="notice-item">
          <Badge color="volcano" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is volcano event</Ellipsis>
        </div>
      </template>
    </template>
    <template #monthValue="{ monthObject, timestamp }">
      <template v-if="[1, 7].includes(monthObject.month)">
        <template v-if="monthObject.month === 1">二月</template>
        <template v-if="monthObject.month === 7">八月</template>
      </template>
    </template>
    <template #monthContent="{ monthObject, timestamp }">
      <template v-if="[1, 7].includes(monthObject.month)">
        <div class="notice-item">
          <Badge status="warning" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is warning event.</Ellipsis>
        </div>
        <div class="notice-item">
          <Badge status="success" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is usual event.</Ellipsis>
        </div>
        <div class="notice-item">
          <Badge color="volcano" />
          <Ellipsis class="notice-text" :tooltip-max-width="240">This is volcano event</Ellipsis>
        </div>
      </template>
    </template>
  </Calendar>
</template>
<style lang="less" scoped>
/* 每条通知事项独占一行:状态圆点固定宽度,文本交给 Ellipsis 截断并悬浮提示 */
.notice-item {
  display: flex;
  align-items: center;
  gap: 8px;
}
.notice-text {
  flex: 1;
  min-width: 0;
}
</style>

自定义插槽 ​

2026年
2026年
10月
10月
月
年
MonTueWedThuFriSatSun
28日
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日
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format } from 'date-fns'
const slotDate = ref(Date.now())
watchEffect(() => {
  console.log('slotDate', slotDate.value)
})
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Calendar v-model:value="slotDate" @panelChange="onPanelChange">
    <template #week="{ defaultWeek, week, timestamp }">
      {{ format(timestamp, 'EEE') }}
    </template>
    <template #dateValue="{ dateObject, timestamp }"> {{ dateObject.date }}日 </template>
    <template #monthValue="{ monthObject, timestamp }">
      {{ format(timestamp, 'MMMM') }}
    </template>
  </Calendar>
</template>

选择功能 ​

You selected date: 2030-10-06
2030年
2030年
10月
10月
月
年
一二三四五六日
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
3
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format } from 'date-fns'
import { useMessage } from 'vue-amazing-ui'
const selectDate = ref(new Date('2030-10-06').getTime())
const message = useMessage()
watchEffect(() => {
  console.log('selectDate', selectDate.value)
})
function onSelect(date: string | number, source: 'date' | 'month') {
  console.log('select', date, source)
  message.success(format(date, 'yyyy-MM-dd'))
}
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Flex vertical>
    <Alert type="info" :message="`You selected date: ${format(selectDate, 'yyyy-MM-dd')}`" />
    <Calendar v-model:value="selectDate" @select="onSelect" @panelChange="onPanelChange" />
  </Flex>
</template>

禁用日期 ​

display:
panel
card
禁用指定日期 (以今天为准的前三天和后三天)
2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
禁用所有周末 (星期六 & 星期日)
2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format, subDays, addDays } from 'date-fns'
import { useMessage } from 'vue-amazing-ui'
const disableDate = ref(Date.now())
const message = useMessage()
const displayOptions = [
  {
    label: 'panel',
    value: 'panel'
  },
  {
    label: 'card',
    value: 'card'
  }
]
const disabledDisplay = ref('panel')
watchEffect(() => {
  console.log('disableDate', disableDate.value)
})
function disabledDate(timestamp: number): boolean {
  if (subDays(Date.now(), 4).getTime() < timestamp && timestamp < addDays(Date.now(), 3).getTime()) {
    return true
  }
  return false
}
function disabledWeekend(timestamp: number): boolean {
  return ['6', '7'].includes(format(timestamp, 'i'))
}
function onSelect(date: string | number, source: 'date' | 'month') {
  console.log('select', date, source)
  message.success(format(date, 'yyyy-MM-dd'))
}
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Flex vertical>
    <Space align="center">
      display:<Radio :options="displayOptions" v-model:value="disabledDisplay" button button-style="solid" />
    </Space>
    <Space>
      <Flex vertical>
        <Alert type="info" message="禁用指定日期 (以今天为准的前三天和后三天)" />
        <Calendar
          v-model:value="disableDate"
          :disabled-date="disabledDate"
          :display="disabledDisplay"
          @select="onSelect"
          @panelChange="onPanelChange"
        />
      </Flex>
      <Flex vertical>
        <Alert type="info" message="禁用所有周末 (星期六 & 星期日)" />
        <Calendar
          v-model:value="disableDate"
          :disabled-date="disabledWeekend"
          :display="disabledDisplay"
          @select="onSelect"
          @panelChange="onPanelChange"
        />
      </Flex>
    </Space>
  </Flex>
</template>

自定义日期格式 ​

You selected date: 2026-10-13
2026年
2026年
10月
10月
月
年
一二三四五六日
28
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format } from 'date-fns'
const dateStr = ref(format(Date.now(), 'yyyy-MM-dd'))
watchEffect(() => {
  console.log('dateStr', dateStr.value)
})
function onPanelChange(date: string | number, info: { year: number; month?: number }, mode: 'month' | 'year') {
  console.log('panelChange', date, info, mode)
}
</script>
<template>
  <Flex vertical>
    <Alert type="info" :message="`You selected date: ${dateStr}`" />
    <Calendar v-model:value="dateStr" value-format="yyyy-MM-dd" @panelChange="onPanelChange" />
  </Flex>
</template>

APIs ​

Calendar ​

参数说明类型默认值
display日历展示方式,面板/卡片'panel' | 'card''panel'
mode初始模式'month' | 'year''month'
header自定义日历头部内容stringundefined
yearSelectProps年选择器 props,参考 Select PropsSelectProps{}
monthSelectProps月选择器 props,参考 Select PropsSelectProps{}
modeRadioProps模式切换器 props,参考 Radio PropsRadioProps{}
startDayOfWeek一周的开始是星期几,0-6,0 是周一CalendarDayOfWeek0
dateStrip日历面板默认会显示六周的日期,当最后一周的日期不包含当月日期时,是否去掉booleantrue
dateFormat自定义日期展示格式(date: number, timestamp: number) => stringundefined
weekFormat自定义星期展示格式 (defaultWeek: CalendarDefaultWeek, week: number, timestamp: number) => stringundefined
monthFormat自定义月展示格式(month: number, timestamp: number) => stringundefined
disabledDate不可选择的日期(timestamp: number) => booleanundefined
valueFormat被选中日期的格式,默认为时间戳;参考 formatstringundefined
value
v-model
当前被选中的日期string | numberundefined

DayOfWeek Type ​

名称值
DayOfWeek0 | 1 | 2 | 3 | 4 | 5 | 6

DefaultWeek Type ​

名称值
DefaultWeek'一' | '二' | '三' | '四' | '五' | '六' | '日'

DateItem Type ​

名称说明类型默认值
type类型'date'undefined
dateObject日期对象{ date: number, month: number, year: number }undefined
timestamp当天开始的时间戳numberundefined
inCurrentMonth是否在当前月booleanundefined
isCurrentDate是否为今天booleanundefined

MonthItem Type ​

名称说明类型默认值
type类型'month'undefined
monthObject月份对象{ month: number, year: number }undefined
timestamp当月开始的时间戳numberundefined
isCurrent是否为当前月booleanundefined

Slots ​

名称说明用法
header自定义日历头部内容v-slot:header
week自定义周展示v-slot:week="{ defaultWeek, week, timestamp }"
dateValue自定义日期展示v-slot:dateValue="{ type, dateObject, timestamp, inCurrentMonth, isCurrentDate }"
dateContent自定义日期内容展示v-slot:dateContent="{ type, dateObject, timestamp, inCurrentMonth, isCurrentDate }"
monthValue自定义月份展示v-slot:monthValue="{ type, monthObject, timestamp, isCurrent }"
monthContent自定义月份内容展示v-slot:monthContent="{ type, monthObject, timestamp, isCurrent }"

Events ​

名称说明类型
change日期变化时的回调(date: string | number, dateOrMonth: CalendarDateItem['dateObject'] | CalendarMonthItem['monthObject']) => void
panelChange日期面板变化的回调(date: string | number, info: { year: number, month?: number }, mode: 'month' | 'year') => void
select选择日期回调,包含来源信息(date: string | number, source: 'date' | 'month') => void

Released under the MIT License.