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 的 Calendar 日历组件是一个功能全面、设计精良的日期选择解决方案。从基础的单日期选择到复杂的打卡签到、价格日历,这些都能轻松应对。
使用建议:
- 选择合适的展示模式:弹窗模式适合临时选择,页面模式适合常驻展示
- 合理利用默认选中:通过
default-date或default-select-today提升用户体验 - 注意日期格式:所有日期参数统一使用
YYYY-MM-DD格式 - 自定义插槽优先级:使用
date插槽时会覆盖农历、节日等默认显示 - 打卡模式注意:
today-checked优先级高于checkedDates的自动判断
功能使用建议:
- 如需农历功能,请确保使用支持该功能的版本
- 如需打卡签到、节假日、自定义插槽等高级功能,请使用最新版本
如果你正在开发 uni-app 项目,需要一个功能强大、易于定制的日历组件,uView Pro 的 Calendar 值得一试,快来体验一下。
