普通视图

发现新文章,点击刷新页面。
今天 — 2026年4月20日首页

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

2026年4月20日 15:15

一、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 控制弹窗显示/隐藏 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 日历组件是一个功能全面、设计精良的日期选择解决方案。从基础的单日期选择到复杂的打卡签到、价格日历,这些都能轻松应对。

使用建议:

  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
  • 📦 开源地址:GithubGitee,欢迎 Star
  • 💬 技术交流:如有问题欢迎在评论区留言讨论

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

❌
❌