Skip to content

日历 Calendar

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

何时使用

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

参考文档

基本使用

2025年
2月
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
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>

卡片模式

2025年
2月
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
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
2025年
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
2025年
2月
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
日历
2025年
2月
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
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:
周一
周二
周三
周四
周五
周六
周日
2025年
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
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
2025年
2月
27
28
29
30
31
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
01
02
Week format
2025年
2月
周一周二周三周四周五周六周日
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
Month format
2025年
一月
二月
三月
四月
五月
六月
七月
八月
九月
十月
十一月
十二月
2025年
2月
MondayTuesdayWednesdayThursdayFridaySaturdaySunday
27th
28th
29th
30th
31st
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
1st
2nd
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>

通知事项日历

2025年
2月
27
28
29
30
31
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
1
2
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)">
        <Badge status="warning" text="This is warning event." />
        <Badge status="success" text="This is usual event." />
        <Badge color="volcano" text="This is volcano event" />
      </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)">
        <Badge status="warning" text="This is warning event." />
        <Badge status="success" text="This is usual event." />
        <Badge color="volcano" text="This is volcano event" />
      </template>
    </template>
  </Calendar>
</template>
<style lang="less" scoped>
.m-badge {
  width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
</style>

自定义插槽

2025年
2月
MonTueWedThuFriSatSun
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日
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
2025年
2月
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format } from 'date-fns'
const selectDate = ref(new Date('2030-10-06').getTime())
const message = ref()
watchEffect(() => {
  console.log('selectDate', selectDate.value)
})
function onSelect(date: string | number, source: 'date' | 'month') {
  console.log('select', date, source)
  message.value.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>
  <Message ref="message" />
</template>

禁用日期

display:
panel
card
禁用指定日期 (以今天为准的前三天和后三天)
2025年
2月
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
禁用所有周末 (星期六 & 星期日)
2025年
2月
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
Show Code
vue
<script lang="ts" setup>
import { ref, watchEffect } from 'vue'
import { format, subDays, addDays } from 'date-fns'
const disableDate = ref(Date.now())
const message = ref()
const displayOptions = [
  {
    label: 'panel',
    value: 'panel'
  },
  {
    label: 'card',
    value: 'card'
  }
]
const display = 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.value.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="display" button button-style="solid" />
    </Space>
    <Space>
      <Flex vertical>
        <Alert type="info" message="禁用指定日期 (以今天为准的前三天和后三天)" />
        <Calendar v-model:value="disableDate" :disabled-date="disabledDate" :display="display" @select="onSelect" @panelChange="onPanelChange" />
      </Flex>
      <Flex vertical>
        <Alert type="info" message="禁用所有周末 (星期六 & 星期日)" />
        <Calendar v-model:value="disableDate" :disabled-date="disabledWeekend" :display="display" @select="onSelect" @panelChange="onPanelChange" />
      </Flex>
    </Space>
  </Flex>
  <Message ref="message" />
</template>

自定义日期格式

You selected date: 2025-02-21
2025年
2月
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
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自定义日历头部内容string | slotundefined
startDayOfWeek一周的开始是星期几,0-60 是周一DayOfWeek0
dateStrip日历面板默认会显示六周的日期,当最后一周的日期不包含当月日期时,是否去掉booleantrue
dateFormat自定义日期展示格式(date: number, timestamp: number) => stringundefined
weekFormat自定义星期展示格式 (defaultWeek: DefaultWeek, 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:dateValue="{ type, monthObject, timestamp, isCurrent }"
monthContent自定义月份内容展示v-slot:dateContent="{ type, monthObject, timestamp, isCurrent }"

Events

名称说明类型
change日期变化时的回调(date: string | number, dateOrMonth: DateItem['dateObject'] | MonthItem['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.