uni-app 全能日历组件,支持农历、酒店预订、打卡签到、价格日历多种场景

92 阅读10分钟

一、uView Pro 的 Calendar 组件

在 uni-app 开发中,日期选择是一个高频需求场景。无论是酒店预订的入住离店时间选择、电商平台的商品预约、还是日常应用的打卡签到,一个功能完善、体验优秀的日历组件都是必不可少的。

uView Pro 作为 uni-app 生态中备受关注的 Vue3 组件库,其 Calendar 日历组件 经过了多个版本的迭代优化,从最初的基础日期选择,逐步演进为支持农历显示、打卡签到、节假日标记、自定义价格日历等丰富功能的综合型组件。

本文将深入解析 uView Pro Calendar 组件的核心特性、实现原理以及实际应用场景,帮助你快速掌握这个强大的日期选择利器。

二、组件概览:功能特性总览

0.png

uView Pro 的 Calendar 日历组件具有以下核心特性:

基础功能

  • ✅ 支持单日期选择和日期范围选择两种模式
  • ✅ 底部弹窗和页面嵌入两种展示方式
  • ✅ 年月切换导航,支持自定义年份范围
  • ✅ 日期范围限制,防止选择无效日期

进阶功能

  • ✅ 农历显示支持,自动计算农历日期
  • ✅ 打卡签到模式,支持已打卡/未打卡状态展示
  • ✅ 节假日和加班日标记,显示"休"/"班"标识
  • ✅ 内置中国传统节日,支持自定义节日配置
  • ✅ 自定义日期内容插槽,适用于价格日历等场景

交互优化

  • ✅ 默认选中今天,支持指定默认日期
  • ✅ 只读模式,禁止日期选择
  • ✅ 选中效果可配置,适应不同视觉需求

三、基础使用:快速上手

3.1 单日期选择模式

单日期选择是最常用的场景,比如选择生日、预约日期等。

1.png

<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 日期范围选择模式

范围选择适用于酒店预订、行程规划等需要起止时间的场景。

2.png

<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 组件内置了农历计算功能,开启后会自动显示农历日期。

6.png

<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 事件
  • 支持所有其他功能(农历、打卡、节假日等)

7.png

4.3 打卡签到模式

打卡签到日历也是近期咨询我比较多的功能,Calendar 组件专门为此设计了打卡模式。

3.png

<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>

打卡模式的显示规则:

  1. 今日已打卡:绿色圆形背景,显示白色对勾
  2. 其他已打卡日期:橙色圆形背景,显示日期
  3. 未打卡日期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.png

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>

优先级规则:

  1. 特定年份格式(YYYY-MM-DD)优先级最高
  2. 每年固定格式(MM-DD)次之
  3. 内置节日优先级最低

4.6 自定义日期内容:价格日历

通过 date 插槽,可以完全自定义每个日期的显示内容,常用于电商价格日历场景。

5.png

<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()
}

渲染流程:

  1. 计算当月第一天是星期几,生成前置空白格子
  2. 计算当月总天数,生成日期格子
  3. 根据选中状态计算每个格子的样式
  4. 如果有农历,调用农历转换库计算农历日期

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控制弹窗显示/隐藏booleanfalse
mode选择模式:date 单选 / range 范围stringdate
is-page是否在页面中直接显示booleanfalse
show-lunar是否显示农历booleanfalse
readonly是否只读booleanfalse
default-date默认选中日期(单选模式)string-
start-date默认开始日期(范围模式)string-
end-date默认结束日期(范围模式)string-
default-select-today默认选中今天booleantrue
min-date最小可选日期string1950-01-01
max-date最大可选日期string今天
min-year最小可选年份number/string1950
max-year最大可选年份number/string2050
change-year是否显示年份切换按钮booleantrue
change-month是否显示月份切换按钮booleantrue
active-bg-color选中日期背景色string主题色
active-color选中日期文字颜色string白色
range-bg-color范围内日期背景色string主题色浅
range-color范围内日期文字颜色string主题色
start-text开始日期提示文字string开始
end-text结束日期提示文字string结束
tool-tip顶部提示文字string选择日期
closeable是否显示关闭图标booleantrue
mask-close-able点击遮罩是否关闭booleantrue
safe-area-inset-bottom底部安全区适配booleanfalse
border-radius弹窗圆角number/string20
z-index弹窗层级number/string10075
is-active-current选中日期是否高亮booleantrue
checkin-mode是否启用打卡模式booleanfalse
checked-dates已打卡日期列表array[]
today-checked今日是否已打卡booleanfalse
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是否显示内置节日booleanfalse
festivals自定义节日配置object{}
festival-color节日文字颜色string主题色
use-date-slot是否启用日期插槽booleanfalse

Events 事件

事件名说明回调参数
change日期选择完成时触发CalendarChangeDate / CalendarChangeRange

Slots 插槽

名称说明
tooltip自定义顶部提示内容
date自定义日期内容(作用域插槽)

更多功能及用法参考 uView Pro 日历文档:uviewpro.cn/zh/componen…

八、总结

uView Pro 的 Calendar 日历组件是一个功能全面、设计精良的日期选择解决方案。从基础的单日期选择到复杂的打卡签到、价格日历,这些都能轻松应对。

使用建议:

  1. 选择合适的展示模式:弹窗模式适合临时选择,页面模式适合常驻展示
  2. 合理利用默认选中:通过 default-datedefault-select-today 提升用户体验
  3. 注意日期格式:所有日期参数统一使用 YYYY-MM-DD 格式
  4. 自定义插槽优先级:使用 date 插槽时会覆盖农历、节日等默认显示
  5. 打卡模式注意today-checked 优先级高于 checkedDates 的自动判断

功能使用建议:

  • 如需农历功能,请确保使用支持该功能的版本
  • 如需打卡签到、节假日、自定义插槽等高级功能,请使用最新版本

如果你正在开发 uni-app 项目,需要一个功能强大、易于定制的日历组件,uView Pro 的 Calendar 值得一试,快来体验一下。

九、资源

  • 📚 uView Pro 官方文档:uviewpro.cn
  • 🗓 Calendar日历文档:uviewpro.cn/zh/componen…
  • 📦 开源地址:GithubGitee,欢迎 Star
  • 📱WX小程序:搜索 uViewPro 直接体验
  • 💬 技术交流:如有相关 Calendar 日历建议,也可留言讨论

本文基于 uView Pro v0.5.17 版本编写,部分功能可能需要更新版本支持。