关键在于正确注入价格数据:将含date、price、status字段的对象数组传给selected属性,通过date插槽渲染,确保date为"YYYY-MM-DD"字符串格式,动态更新避免空白或旧数据。

uni-app 酒店房型日历价格展示的关键不是“写日历”,而是“喂对数据”
直接套用 uni-calendar 或 u-calendar 组件本身不支持价格展示——它只管日期交互,价格、库存、房型状态这些必须靠你手动注入。核心逻辑是:把每个日期的价格/可售状态,作为「标记数据」传给组件的 selected 属性,再用插槽(slot)或自定义样式把它渲染出来。
selected 数组必须严格按 {date: "YYYY-MM-DD", price: number, status: string} 格式组织
很多人卡在这一步:以为 selected 只能标“已打卡”小红点,其实它是通用数据容器。只要字段名不冲突,你可以塞任意业务字段进去,后续在插槽里取用。
-
date必须是字符串格式"2026-10-30",不能是new Date()或时间戳 -
price和status是你自定义字段,但必须和插槽模板里的变量名一致(比如item.price) - 未传入
selected的日期,插槽默认渲染为空白;传了但没写price字段,该日期就显示空价(别漏赋值) - 小程序端对数组长度敏感,3个月日历建议最多传 92 条,超长可能触发渲染卡顿或白屏
用 scoped slot 替换默认日期单元格,展示价格+房态
官方组件都支持 date 插槽(u-calendar 叫 #date,uni-calendar 叫 date),这是唯一可控的渲染入口。不要试图改组件源码或 hack CSS。
<u-calendar mode="range" :selected="priceData" >
<template #date="{ item }">
<view class="price-cell">
<text class="date-num">{{ item.date.split('-')[2] }}</text>
<text v-if="item.price" class="price">¥{{ item.price }}</text>
<text v-else class="unavailable">满</text>
<view v-if="item.status === 'soldout'" class="soldout-badge">售罄</view>
</view>
</template>
</u-calendar>
- 注意:插槽内
item就是你selected数组里对应日期的对象,不是原始日期对象 - 如果某天没价格数据(比如未来还没发布房态),
item会是空对象,需加v-if="item?.price"防报错 - H5 端支持 flex 布局,小程序端慎用
gap,用margin更稳妥
日期范围限制和默认选中要分开配置,否则入住离店逻辑错乱
酒店场景下,用户选择的是「入住日 → 离店日」区间,不是单个日期。这时候 mode="range" 是必须的,但光设 start-date 和 end-date 不够——它们只禁用按钮,不控制初始滚动位置和默认高亮。
- 让日历打开时自动定位到今天:
:date="'2026-10-30'"(当前时间动态生成) - 限制最早可选入住日(比如不能选今天之前):
:min-date="'2026-10-30'",注意这是字符串 - 限制最晚可选离店日(比如最多住30天):
:max-date="maxDateStr",需用dayjs或手算生成 - 预设默认入住/离店日(如默认住2晚):
:default-date="['2026-10-30', '2026-11-01']",数组顺序固定为 [入住, 离店]
价格日历最易被忽略的点:价格数据必须和用户最终确认的日期范围强绑定。比如用户滑动切换月份后,新加载的月份价格若没及时更新进 selected,插槽就会渲染旧数据或空白——这需要你在 @change 事件里监听月份滚动,主动触发价格接口拉取。


















