uni-app 全能日历组件,支持农历、酒店预订、打卡签到、价格日历多种场景
一、uView Pro 的 Calendar 组件
在 uni-app 开发中,日期选择是一个高频需求场景。无论是酒店预订的入住离店时间选择、电商平台的商品预约、还是日常应用的打卡签到,一个功能完善、体验优秀的日历组件都是必不可少的。
uView Pro 作为 uni-app 生态中备受关注的 Vue3 组件库,其 Calendar 日历组件 经过了多个版本的迭代优化,从最初的基础日期选择,逐步演进为支持农历显示、打卡签到、节假日标记、自定义价格日历等丰富功能的综合型组件。
本文将深入解析 uView Pro Calendar 组件的核心特性、实现原理以及实际应用场景,帮助你快速掌握这个强大的日期选择利器。
二、组件概览:功能特性总览
uView Pro 的 Calendar 日历组件具有以下核心特性:
基础功能
- ✅ 支持单日期选择和日期范围选择两种模式
- ✅ 底部弹窗和页面嵌入两种展示方式
- ✅ 年月切换导航,支持自定义年份范围
- ✅ 日期范围限制,防止选择无效日期
进阶功能
- ✅ 农历显示支持,自动计算农历日期
- ✅ 打卡签到模式,支持已打卡/未打卡状态展示
- ✅ 节假日和加班日标记,显示"休"/"班"标识
- ✅ 内置中国传统节日,支持自定义节日配置
- ✅ 自定义日期内容插槽,适用于价格日历等场景
交互优化
- ✅ 默认选中今天,支持指定默认日期
- ✅ 只读模式,禁止日期选择
- ✅ 选中效果可配置,适应不同视觉需求
三、基础使用:快速上手
3.1 单日期选择模式
单日期选择是最常用的场景,比如选择生日、预约日期等。
<template>
<view>
<u-calendar v-model="show" mode="date" @change="onChange"></u-calendar>
<u-button @click="show = true">选择日期</u-button>
</view>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CalendarChangeDate } from 'uview-pro/types/global'
const show = ref(false)
function onChange(e: CalendarChangeDate) {
console.log('选择的日期:', e.result)
console.log('星期:', e.week)
console.log('是否今天:', e.isToday)
}
</script>
回调参数说明:
| 属性 | 说明 | 类型 |
|---|---|---|
| year | 选择的年份 | number |
| month | 选择的月份 | number |
| day | 选择的日期 | number |
| result | 格式化的日期字符串,如 "2024-06-15" | string |
| week | 星期文字,如 "星期六" | string |
| isToday | 是否选择了今天 | boolean |
3.2 日期范围选择模式
范围选择适用于酒店预订、行程规划等需要起止时间的场景。
<template>
<u-calendar
v-model="show"
mode="range"
start-text="入住"
end-text="离店"
@change="onRangeChange"
>
<template #tooltip>
<view class="tip">请选择入住和离店时间</view>
</template>
</u-calendar>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import type { CalendarChangeRange } from 'uview-pro/types/global'
const show = ref(false)
function onRangeChange(e: CalendarChangeRange) {
console.log('入住日期:', e.startDate)
console.log('离店日期:', e.endDate)
console.log('共', e.endDay - e.startDay + 1, '晚')
}
</script>
范围模式回调参数:
| 属性 | 说明 |
|---|---|
| startDate / endDate | 起始/结束日期字符串 |
| startYear / endYear | 起始/结束年份 |
| startMonth / endMonth | 起始/结束月份 |
| startDay / endDay | 起始/结束日期 |
| startWeek / endWeek | 起始/结束星期 |
四、进阶功能详解
4.1 农历显示
Calendar 组件内置了农历计算功能,开启后会自动显示农历日期。
<u-calendar
v-model="show"
mode="date"
:show-lunar="true"
@change="onLunarChange"
></u-calendar>
开启农历后,回调参数会增加 lunar 对象:
{
day: 15,
month: 6,
result: "2024-06-15",
lunar: {
dayCn: '初十', // 农历日
monthCn: '五月', // 农历月
year: 2024, // 农历年
weekCn: "星期六" // 农历星期
}
}
农历显示会自动处理闰月、大小月等复杂逻辑,无需开发者关心底层实现。
4.2 页面嵌入模式
除了弹窗模式,组件还支持直接嵌入页面显示,适用于需要常驻展示日历的场景。
<template>
<view class="calendar-page">
<u-calendar
:is-page="true"
mode="date"
@change="onChange"
></u-calendar>
</view>
</template>
页面模式的特点:
- 不显示弹窗和确定按钮
- 选择日期后自动触发
change事件 - 支持所有其他功能(农历、打卡、节假日等)
4.3 打卡签到模式
打卡签到日历也是近期咨询我比较多的功能,Calendar 组件专门为此设计了打卡模式。
<template>
<u-calendar
:is-page="true"
:checkin-mode="true"
:checked-dates="checkedDates"
:today-checked="todayChecked"
></u-calendar>
</template>
<script setup>
import { ref } from 'vue'
// 已打卡日期列表
const checkedDates = ref([
'2024-01-01',
'2024-01-02',
'2024-01-03',
'2024-01-05'
])
// 今日打卡状态(优先级高于自动判断)
const todayChecked = ref(true)
</script>
打卡模式的显示规则:
- 今日已打卡:绿色圆形背景,显示白色对勾
- 其他已打卡日期:橙色圆形背景,显示日期
-
未打卡日期(
checkin-mode为 true 时):灰色圆形背景
颜色自定义:
| 属性 | 说明 | 默认值 |
|---|---|---|
| checked-bg-color | 已打卡日期背景色 | 橙色(warning) |
| today-checked-bg-color | 今日已打卡背景色 | 绿色(success) |
| unchecked-bg-color | 未打卡日期背景色 | 灰色(light) |
4.4 节假日与加班日标记
组件支持显示节假日和加班日标记,方便用户了解日期属性。
<template>
<u-calendar
:is-page="true"
:holidays="holidays"
:workdays="workdays"
></u-calendar>
</template>
<script setup>
import { ref } from 'vue'
// 节假日(元旦假期)
const holidays = ref(['2024-01-01', '2024-01-02'])
// 加班日(调休上班)
const workdays = ref(['2024-01-06', '2024-01-07'])
</script>
显示效果:
- 节假日:日期右上角显示红色"休"字
- 加班日:日期右上角显示蓝色"班"字
- 选中状态下,"休"/"班"字变为白色
4.5 节日显示
组件内置了中国传统节日,同时支持自定义节日配置。
内置节日(show-festival 为 true 时自动显示):
- 元旦(1月1日)
- 情人节(2月14日)
- 妇女节(3月8日)
- 植树节(3月12日)
- 愚人节(4月1日)
- 劳动节(5月1日)
- 青年节(5月4日)
- 儿童节(6月1日)
- 建党节(7月1日)
- 建军节(8月1日)
- 教师节(9月10日)
- 国庆节(10月1日)
- 光棍节(11月11日)
- 圣诞节(12月25日)
自定义节日:
<template>
<u-calendar
:is-page="true"
:show-festival="true"
:festivals="customFestivals"
></u-calendar>
</template>
<script setup>
import { ref } from 'vue'
const customFestivals = ref({
// 每年固定节日(MM-DD 格式)
'04-04': '清明节',
'05-05': '端午节',
'08-15': '中秋节',
// 特定年份节日(YYYY-MM-DD 格式)- 优先级更高
'2025-04-04': '清明节(2025)',
// 覆盖内置节日(传入空字符串不显示)
'02-14': '',
})
</script>
优先级规则:
- 特定年份格式(
YYYY-MM-DD)优先级最高 - 每年固定格式(
MM-DD)次之 - 内置节日优先级最低
4.6 自定义日期内容:价格日历
通过 date 插槽,可以完全自定义每个日期的显示内容,常用于电商价格日历场景。
<template>
<u-calendar
:is-page="true"
mode="date"
:use-date-slot="true"
>
<template #date="{ date }">
<text :class="getPriceClass(date)">
{{ getPriceText(date) }}
</text>
</template>
</u-calendar>
</template>
<script setup>
import { ref } from 'vue'
// 价格数据
const priceMap = ref({
'2024-01-01': 299,
'2024-01-02': 399,
'2024-01-03': 359,
// ...
})
function getPriceText(date) {
if (date.isToday) return '今天'
const price = priceMap.value[date.date]
return price ? `¥${price}` : ''
}
function getPriceClass(date) {
if (date.isSelected) return 'price-selected'
if (date.isToday) return 'price-today'
return 'price-normal'
}
</script>
<style scoped>
.price-today {
color: #19be6b;
font-weight: bold;
}
.price-normal {
color: #909399;
font-size: 22rpx;
}
.price-selected {
color: #ffffff;
}
</style>
插槽作用域参数:
| 属性 | 说明 | 类型 |
|---|---|---|
| date.year | 年份 | number |
| date.month | 月份 | number |
| date.day | 日期 | number |
| date.date | 完整日期字符串 | string |
| date.week | 星期文字 | string |
| date.isToday | 是否今天 | boolean |
| date.isHoliday | 是否节假日 | boolean |
| date.isWorkday | 是否加班日 | boolean |
| date.isChecked | 是否已打卡 | boolean |
| date.isSelected | 是否选中 | boolean |
| date.lunar | 农历信息 | object |
五、核心实现原理浅析
5.1 日历渲染逻辑
Calendar 组件的日历渲染基于以下核心算法:
// 获取某月天数
function getMonthDay(year: number, month: number) {
return new Date(year, month, 0).getDate()
}
// 获取某月第一天星期几(0-6)
function getWeekday(year: number, month: number) {
let date = new Date(`${year}/${month}/01 00:00:00`)
return date.getDay()
}
渲染流程:
- 计算当月第一天是星期几,生成前置空白格子
- 计算当月总天数,生成日期格子
- 根据选中状态计算每个格子的样式
- 如果有农历,调用农历转换库计算农历日期
5.2 农历计算
组件使用了独立的农历计算工具 Calendar.solar2lunar,将公历日期转换为农历:
function getLunar(year: any, month: any, day: any) {
const val = Calendar.solar2lunar(year, month, day)
return {
dayCn: val.IDayCn, // 农历日(初十、廿三等)
monthCn: val.IMonthCn, // 农历月(正月、五月等)
weekCn: val.ncWeek, // 农历星期
day: val.lDay, // 农历日数字
month: val.lMonth, // 农历月数字
year: val.lYear // 农历年
}
}
5.3 范围选择逻辑
范围选择采用两次点击确定起止时间的交互方式:
function dateClick(dayIdx: number) {
const d = dayIdx + 1
const date = `${year.value}-${month.value}-${d}`
if (props.mode == 'range') {
// 判断是设置开始日期还是结束日期
const compare = new Date(date).getTime() < new Date(startDate.value).getTime()
if (isStart.value || compare) {
// 设置开始日期
startDate.value = date
isStart.value = false
} else {
// 设置结束日期
endDate.value = date
isStart.value = true
// 触发回调
if (props.isPage) btnFix(true)
}
}
}
六、实际应用场景
6.1 酒店预订日历
<u-calendar
v-model="show"
mode="range"
start-text="入住"
end-text="离店"
:min-date="minDate"
:max-date="maxDate"
@change="onDateChange"
>
<template #tooltip>
<view class="hotel-tip">
<text>请选择入住和离店日期</text>
<text class="sub">入住时间14:00后,离店时间12:00前</text>
</view>
</template>
</u-calendar>
6.2 健身打卡应用
<u-calendar
:is-page="true"
:checkin-mode="true"
:checked-dates="monthCheckins"
:today-checked="todayChecked"
:show-lunar="true"
@change="onCheckin"
></u-calendar>
6.3 航班价格日历
<u-calendar
:is-page="true"
mode="date"
:use-date-slot="true"
:default-select-today="false"
:is-active-current="false"
>
<template #date="{ date }">
<view class="flight-price">
<text class="day">{{ date.day }}</text>
<text class="price" v-if="getPrice(date.date)">
¥{{ getPrice(date.date) }}
</text>
</view>
</template>
</u-calendar>
6.4 日程管理应用
<u-calendar
:is-page="true"
:show-festival="true"
:festivals="customFestivals"
:holidays="holidays"
:workdays="workdays"
:default-date="selectedDate"
@change="onSelectDate"
></u-calendar>
七、API 完整参考
Props 属性
| 参数 | 说明 | 类型 | 默认值 |
|---|---|---|---|
| v-model | 控制弹窗显示/隐藏 | boolean | false |
| mode | 选择模式:date 单选 / range 范围 |
string | date |
| is-page | 是否在页面中直接显示 | boolean | false |
| show-lunar | 是否显示农历 | boolean | false |
| readonly | 是否只读 | boolean | false |
| default-date | 默认选中日期(单选模式) | string | - |
| start-date | 默认开始日期(范围模式) | string | - |
| end-date | 默认结束日期(范围模式) | string | - |
| default-select-today | 默认选中今天 | boolean | true |
| min-date | 最小可选日期 | string | 1950-01-01 |
| max-date | 最大可选日期 | string | 今天 |
| min-year | 最小可选年份 | number/string | 1950 |
| max-year | 最大可选年份 | number/string | 2050 |
| change-year | 是否显示年份切换按钮 | boolean | true |
| change-month | 是否显示月份切换按钮 | boolean | true |
| active-bg-color | 选中日期背景色 | string | 主题色 |
| active-color | 选中日期文字颜色 | string | 白色 |
| range-bg-color | 范围内日期背景色 | string | 主题色浅 |
| range-color | 范围内日期文字颜色 | string | 主题色 |
| start-text | 开始日期提示文字 | string | 开始 |
| end-text | 结束日期提示文字 | string | 结束 |
| tool-tip | 顶部提示文字 | string | 选择日期 |
| closeable | 是否显示关闭图标 | boolean | true |
| mask-close-able | 点击遮罩是否关闭 | boolean | true |
| safe-area-inset-bottom | 底部安全区适配 | boolean | false |
| border-radius | 弹窗圆角 | number/string | 20 |
| z-index | 弹窗层级 | number/string | 10075 |
| is-active-current | 选中日期是否高亮 | boolean | true |
| checkin-mode | 是否启用打卡模式 | boolean | false |
| checked-dates | 已打卡日期列表 | array | [] |
| today-checked | 今日是否已打卡 | boolean | false |
| checked-bg-color | 已打卡背景色 | string | 橙色 |
| today-checked-bg-color | 今日已打卡背景色 | string | 绿色 |
| unchecked-bg-color | 未打卡背景色 | string | 灰色 |
| holidays | 节假日列表 | array | [] |
| workdays | 加班日列表 | array | [] |
| holiday-color | 节假日文字颜色 | string | 红色 |
| workday-color | 加班日文字颜色 | string | 蓝色 |
| show-festival | 是否显示内置节日 | boolean | false |
| festivals | 自定义节日配置 | object | {} |
| festival-color | 节日文字颜色 | string | 主题色 |
| use-date-slot | 是否启用日期插槽 | boolean | false |
Events 事件
| 事件名 | 说明 | 回调参数 |
|---|---|---|
| change | 日期选择完成时触发 | CalendarChangeDate / CalendarChangeRange |
Slots 插槽
| 名称 | 说明 |
|---|---|
| tooltip | 自定义顶部提示内容 |
| date | 自定义日期内容(作用域插槽) |
更多功能及用法参考 uView Pro 官方文档 uviewpro.cn
八、总结
uView Pro 的 Calendar 日历组件是一个功能全面、设计精良的日期选择解决方案。从基础的单日期选择到复杂的打卡签到、价格日历,这些都能轻松应对。
使用建议:
- 选择合适的展示模式:弹窗模式适合临时选择,页面模式适合常驻展示
-
合理利用默认选中:通过
default-date或default-select-today提升用户体验 -
注意日期格式:所有日期参数统一使用
YYYY-MM-DD格式 -
自定义插槽优先级:使用
date插槽时会覆盖农历、节日等默认显示 -
打卡模式注意:
today-checked优先级高于checkedDates的自动判断
功能使用建议:
- 如需农历功能,请确保使用支持该功能的版本
- 如需打卡签到、节假日、自定义插槽等高级功能,请使用最新版本
如果你正在开发 uni-app 项目,需要一个功能强大、易于定制的日历组件,uView Pro 的 Calendar 值得一试,快来体验一下。
九、资源
- 📚 uView Pro 官方文档:uviewpro.cn
- 📦 开源地址:Github、Gitee,欢迎 Star
- 💬 技术交流:如有问题欢迎在评论区留言讨论
本文基于 uView Pro v0.5.17 版本编写,部分功能可能需要更新版本支持。