效果图
app.vue
onLaunch:function(options){
this.defaultcache()
}
defaultcache(){
// 入住信息缓存
var arr = this.getDateTime();
var ReserVation = {
reservType:0,//1 人数 2日期
InCheckin:{},//入离日期
peopleArr:[
{title:'成人',num:2},
{title:'儿童',num:0},
{title:'宝子',num:1},
{title:'房间数',num:1},
],//入住人数
IntimeCur:[
{len:0,str:0},
{len:0,str:0}
],//选择日期
timeDataArr:[],//日期数组
}
ReserVation.timeDataArr = arr[0]
ReserVation.IntimeCur = arr[1]
ReserVation.InCheckin = arr[2][0]
uni.setStorageSync('ReserVation',ReserVation)
},
// 获取日期
getDateTime(){
var that = this
var showY = 3;//显示几个月
var timeData = [];//日期数组
var timestamp = Date.parse(new Date());
var date = new Date(timestamp);
//年
var Y = date.getFullYear();
//月
var M = date.getMonth() + 1;
//日
var D = date.getDate();
// 周几和月份天数
var time = {};
var Yday = 0,Mday = 0,data = {},param = {},toDays = 2;//toDays 默认住几天
for(let i = 0;i < showY;i++){
if(12 < (M + i)){
Yday = Y + 1
Mday = (M + i) - 12
}else{
Yday = Y
Mday = M + i
}
time = that.getDaysInMonth(Yday,Mday)
data = {year:Yday,moon:Mday,arr:[],days:time.days,Z:time.Z}
for(let k = 0;k < time.Z;k++){
data.arr.push({date:''});
}
for(let j = 0;j < time.days;j++){
param = {};
param.date = j + 1;
param.Z = that.getDaysInMonth(Yday,Mday,param.date)
param.price = 0;
if(i == 0 && (j + 1) < D){
param.status = 1
}else if(i == 0 && (j + 1) == D){
param.status = 2
}
data.arr.push(param)
}
timeData.push(data)
}
var start = {
len:0,str:D
};
// if(that.timeData[start.len].days < (D + 1)){
// start.len = 1
// start.str = 0
// }
var end = {
len:0,str:D + toDays - 1
}
if(timeData[end.len].days < end.str){
end.str = end.str - timeData[end.len].days
end.len = 1
}
start.str = start.str + parseInt(timeData[start.len].Z) - 1
end.str = end.str + parseInt(timeData[end.len].Z) - 1
var timeCur = [
start,
end
]
var Checkin = {
start_Y:timeData[timeCur[0].len].year,
start_M:timeData[timeCur[0].len].moon,
start_D:timeData[timeCur[0].len].arr[timeCur[0].str].date,
start_Z:timeData[timeCur[0].len].arr[timeCur[0].str].Z,
end_Y:timeData[timeCur[1].len].year,
end_M:timeData[timeCur[1].len].moon,
end_D:timeData[timeCur[1].len].arr[timeCur[1].str].date,
end_Z:timeData[timeCur[1].len].arr[timeCur[1].str].Z,
days:toDays,
}
return [timeData,timeCur,[Checkin]];
},
// 获取周几和月份天数
getDaysInMonth(Y,M,D){
if(D){
return this.getWeekByDate(`${Y}-${M}-${D}`,true)
}
//一号周几
var Z = this.getWeekByDate(`${Y}-${M}-1`);
// 月份天数
var days = new Date(Y, M, 0).getDate();
return {Z,days}
},
// 返回周几
getWeekByDate(dates,status){
let show_day = status?['周日', '周一', '周二', '周三', '周四', '周五', '周六']:['0', '1', '2', '3', '4', '5', '6'];
let date = new Date(dates);
date.setDate(date.getDate());
let day = date.getDay();
return show_day[day];
},
page-reservation.vue
<template>
<view>
<view :class="modalName == 'reservation'?'cu-modal bottom-modal show':'cu-modal bottom-modal'" @touchmove.stop="() => false"
:style="'--CustomBar--:'+CustomBar+'px;z-index:10000;'">
<view class="cu-dialog reservation-index">
<view class="cu-custom">
<view class="cu-bar fixed bg-white dialog-title" :style="'height:'+CustomBar+'px;padding-top:'+StatusBar+'px;'">
<view class="action" @click="showModal('')">
<text class="cuIcon-close" style="font-size: 42upx;"></text>
</view>
<view class="content" :style="'top:'+StatusBar+'px'">
<view>选择入住条件</view>
</view>
</view>
</view>
<!-- 房住 -->
<view class="reser-room">
<view>房住</view>
<view @click="tabreser(1)">
<view v-for="(item,index) in peopleArrCur" :key="index"
:class="item.num > 0?'reser-room-cur':''">
{{item.num + item.title}}
</view>
<view :class="type == 1?'cuIcon-unfold':'cuIcon-unfold reser-rotate'"></view>
</view>
</view>
<!-- list -->
<view class="reser-room-list reser-cur" :style="type != 1?'height:0;box-shadow:0;':''">
<view v-for="(item,index) in peopleArrCur" :key="index">
<view>{{item.title}}</view>
<view class="room-list-count">
<view class="room-list-icon" :class="item.num < 1 || (index == 0 && item.num < 2) || (index == 3 && item.num < 2) || (isType && index == 2)?'list-icon-cur':''"
@click="item.num < 1 || (index == 0 && item.num < 2) || (index == 3 && item.num < 2) || (isType && index == 2)?'':countTap(index,1)">
<view class="cuIcon-move"></view>
</view>
<view>{{item.num}}</view>
<view class="room-list-icon" :class="item.num > 20 || (isType && index == 2)?'list-icon-cur':''"
@click="item.num > 20 || (isType && index == 2)?'':countTap(index,2)">
<view class="cuIcon-add"></view>
</view>
</view>
</view>
</view>
<!-- 日期 -->
<view class="reser-room reser-money">
<view>入离日期</view>
<view @click="tabreser(2)">
<view>
<span class="reser-room-cur">{{Checkin.start_M}}月{{Checkin.start_D}}日</span>
{{Checkin.start_Z}}
</view>
<view class="reser-room-ing">{{Checkin.days}}晚</view>
<view v-if="Checkin.days > 1">
<span class="reser-room-cur">{{Checkin.end_M}}月{{Checkin.end_D}}日</span>
{{Checkin.end_Z}}
</view>
<view :class="type == 2?'cuIcon-unfold':'cuIcon-unfold reser-rotate'"></view>
</view>
</view>
<view class="reser-time" :style="type == 2?'':'height:0;'">
<view>*以下价格为单晚入住参考价</view>
<!-- list -->
<view class="reser-data">
<view v-for="(item,index) in timeTitle" :key="index">{{item}}</view>
</view>
<scroll-view scroll-y class="reser-list"
@scroll="getScrollTop">
<view v-for="(item,index) in timeData" :key="index" class="list-time"
:id="'Time_'+index">
<view>
<view :class="index == scroll_index && type == 2 && modalName == 'reservation'?'reser-fixed':''">{{item.year}}年{{item.moon}}月</view>
</view>
<view>
<view v-for="(cell,cell_index) in item.arr" :key="cell_index" class="list-date"
:class="timeCur[1].str != -1 && timeCur[0].len != timeCur[1].len && (index == timeCur[0].len && timeCur[0].str < cell_index || index == timeCur[1].len && timeCur[1].str > cell_index) ?
'list-cur-one':timeCur[1].str != -1 && timeCur[0].len == timeCur[1].len && (index == timeCur[0].len && timeCur[0].str < cell_index && index == timeCur[1].len && timeCur[1].str > cell_index) ?
'list-cur-one':timeCur[1].len - timeCur[0].len > 1 && index == timeCur[1].len - 1?'list-cur-one':(index == timeCur[0].len && cell_index == timeCur[0].str) ||
(index == timeCur[1].len && cell_index == timeCur[1].str)?'list-cur-two':''"
:style="cell.date?'':'visibility: hidden;'"
@click="cell.status == 1?'':timetap(index,cell_index)">
<view>
<view :class="cell.status == 1?'reser-hui':cell.status == 2?'reser-chen':''">
{{cell.status == 2?'今天':cell.date}}
</view>
<view class="reser-cur-font" v-if="cell.price > 0">
<span v-if="((timeCur[1].str != -1 && timeCur[0].len != timeCur[1].len && (index == timeCur[0].len && timeCur[0].str < cell_index || index == timeCur[1].len && timeCur[1].str > cell_index)) ||
(timeCur[1].str != -1 && timeCur[0].len == timeCur[1].len && (index == timeCur[0].len && timeCur[0].str < cell_index && index == timeCur[1].len && timeCur[1].str > cell_index)) ||
(timeCur[1].len - timeCur[0].len > 1 && index == timeCur[1].len - 1) || ((index == timeCur[0].len && cell_index == timeCur[0].str) ||
(index == timeCur[1].len && cell_index == timeCur[1].str)))">
¥{{cell.price}}
</span>
</view>
<view class="reser-cur-font" v-if="(index == timeCur[0].len && cell_index == timeCur[0].str) ||
(index == timeCur[1].len && cell_index == timeCur[1].str)">{{(index == timeCur[0].len && cell_index == timeCur[0].str)?'入住':'离店'}}</view>
</view>
</view>
</view>
</view>
<view class="wdh" style="height: 162px;"></view>
</scroll-view>
<view class="reser-button">
<button class="cu-btn round" @click="btnConfirm">确定</button>
</view>
</view>
</view>
</view>
</view>
</template>
<script>
export default{
data(){
return{
StatusBar:this.StatusBar,
CustomBar: this.CustomBar,
type:0,
timeTitle:['周日','周一','周二','周三','周四','周五','周六'],
timeData:[],
timeCur:[
{len:0,str:0},
{len:0,str:0}
],
scroll_index:-1,//fiexd日期
Checkin:{
start_M:'',
start_D:'',
start_Z:'',
end_M:'',
end_D:'',
end_Z:'',
days:'',
},//入离日期
peopleArrCur:[],
}
},
name: 'page-reservation',
props: {
modalName: {
type: String,
default: ''
},
ReserVation: {
type: Object,
default: {}
},
isType: {
type: [Boolean, String],
default: false
},
},
created(){
//默认显示日期或者人数
this.type = this.ReserVation.reservType
//房住
this.peopleArrCur = this.ReserVation.peopleArr
//选择的入住时间
this.timeCur = this.ReserVation.IntimeCur
//日期数组
this.timeData = this.ReserVation.timeDataArr
//入住时间信息
this.Checkin = this.ReserVation.InCheckin
this.list()
},
methods:{
list(){
var that = this
setTimeout(() => {
that.scroll_index = 0
},500)
setTimeout(() => {
that.getDateHeight();
},1000)
},
timetap(index,cell_index){
var that = this
if(that.timeCur[1].str != -1 || (cell_index < that.timeCur[0].str && index == that.timeCur[0].len) || (index < that.timeCur[0].len)){//选择开始
that.timeCur[0].len = index
that.timeCur[0].str = cell_index
that.timeCur[1].len = index
that.timeCur[1].str = -1
that.Checkin = {
start_M:that.timeData[that.timeCur[0].len].moon,
start_D:that.timeData[that.timeCur[0].len].arr[that.timeCur[0].str].date,
start_Z:that.timeData[that.timeCur[0].len].arr[that.timeCur[0].str].Z,
end_M:'',
end_D:'',
end_Z:'',
days:1,
}
}else{//选择结束
var number = 0
if(that.timeCur[0].len == index){
number = cell_index - that.timeCur[0].str + 1
}else{
var time = index - that.timeCur[0].len;
number += (that.timeData[that.timeCur[0].len].arr.length - that.timeCur[0].str)
for(let i = that.timeCur[0].len + 1;i < index;i++){
number += that.timeData[i].days
}
number += (cell_index - parseInt(that.timeData[index].Z)) + 1
}
if(number > 30){
getApp().Tips('最多选择三十天')
}else{
that.timeCur[1].len = index
that.timeCur[1].str = cell_index
that.getCheckinDays(number)
}
}
},
// 入离日期
getCheckinDays(D){
var that = this
that.Checkin = {
start_Y:that.timeData[that.timeCur[0].len].year,
start_M:that.timeData[that.timeCur[0].len].moon,
start_D:that.timeData[that.timeCur[0].len].arr[that.timeCur[0].str].date,
start_Z:that.timeData[that.timeCur[0].len].arr[that.timeCur[0].str].Z,
end_Y:that.timeData[that.timeCur[1].len].year,
end_M:that.timeData[that.timeCur[1].len].moon,
end_D:that.timeData[that.timeCur[1].len].arr[that.timeCur[1].str].date,
end_Z:that.timeData[that.timeCur[1].len].arr[that.timeCur[1].str].Z,
days:D,
}
},
btnConfirm(){
if(this.Checkin.days < 2){
return getApp().Tips('请选择离店时间~')
}
this.$emit('getHotelData', this.peopleArrCur,this.Checkin,this.timeCur);
},
getDateHeight(){
var that = this
var text = ''
for(let i = 0;i < that.timeData.length;i++){
text = '#Time_' + i
uni.createSelectorQuery().in(that).select(text).boundingClientRect(function (res) {
that.timeData[i].TimeHiehgt = res.height + (i == 0?0:that.timeData[i - 1].TimeHiehgt) - 5
}).exec();
}
},
getScrollTop(e){
var i = this.scroll_index > 0?this.scroll_index - 1:0;
for(i;i < this.timeData.length;i++){
if(e.detail.scrollTop < this.timeData[i].TimeHiehgt){
this.scroll_index = i;
break;
}
}
},
showModal(target){
this.$emit('showModal', target);
},
countTap(index,type){
if(type == 1){
this.peopleArrCur[index].num--
}else{
this.peopleArrCur[index].num++
}
},
tabreser(type){
var that = this
if(that.type == type){
that.type = 0
}else{
that.type = type
if(type == 2){
that.scroll_index = -1
setTimeout(() => {
that.scroll_index = 0
},500)
}
}
},
},
}
</script>
<style>
/* 预定酒店 */
.reservation-index{height: 100vh;}
.dialog-title{position: relative !important;z-index: 0 !important;}
.reser-room{font-size: 26upx;display: flex;align-items: center;justify-content:space-between;color: #666;
height:53px;padding: 0 30upx;background: #fff;width: 100%;float: left;}
.reser-room>view:nth-child(2){display: flex;align-items:center;}
.reser-room>view:nth-child(2)>view{margin-left: 20upx;}
.reser-room>view:nth-child(2)>.cuIcon-unfold{color: #000;}
.reser-cur{box-shadow: inset 0rpx 3rpx 6rpx 1rpx rgba(0,0,0,0.16);}
.reser-room-cur{color: #FC9C39;}
.reser-room-list{width: 100%;float: left;padding: 0 30upx;transition: height 0.3s;background: #fff;height: 200px;overflow: hidden;}
.reser-room-list>view{width: 100%;float: left;height:50px;display:flex;align-items:center;
justify-content:space-between;font-size: 26upx;color: #666;}
.room-list-count{display: flex;align-items: center;}
.room-list-icon{display: flex;align-items: center;justify-content: center;width: 38upx;height: 38upx;border-radius: 50%;color: #fff;
background-color: #FF9800;}
.list-icon-cur{background-color: #939393 !important;}
.room-list-count>view:nth-child(2){margin: 0 10upx;min-width: 34upx;}
.cuIcon-unfold{transform:rotate(0deg);transition: all 0.3s;margin-left: 6upx !important;}
.reser-rotate{transform:rotate(-90deg);}
.reser-room-ing{background-color: #FAFAFA;border-radius: 20upx;padding: 0 20upx;height: 40upx;line-height: 40upx;font-size: 20upx;color: #666;}
/* 日期 */
.reser-money{margin-top: 10px;}
.reser-time{width: 100%;height:calc(100vh - 116px - var(--CustomBar--)) ;background-color: #fff;float: left;transition: height 0.3s;overflow: hidden;}
.reser-time>view{width: 100%;float: left;}
.reser-time>view:nth-child(1){background: #FFE3C6;color: #5F5F5F;height: 31px;display: flex;align-items: center;justify-content: center;}
.reser-data{width: calc(100% - 60upx) !important;float: left;height: 50px;display: flex;align-items: center;font-size: 24upx;
color: #5F5F5F;margin: 0 30upx;}
.reser-data>view{width: calc((100% - 60upx) / 7);margin-left: 10upx;}
.reser-data>view:nth-child(1){margin-left: 0;}
.reser-list{width: 100%;float: left;background: #fff;height:calc(100vh - 197px - var(--CustomBar--));}
.list-time{width: 100%;float: left;position: relative;}
.list-time>view:nth-child(1){padding-bottom:20upx;font-size: 30upx;color: #FC9C39;height: 31px;
width: calc(100% - 56upx);margin: 0 28upx;}
.list-time>view:nth-child(1)>view{height: 31px;border-bottom: 1px solid #F2F4F9;background: #fff;z-index: 1;}
.reser-fixed{position: fixed;top: calc(197px + var(--CustomBar--));width: calc(100% - 56upx);}
.list-time>view:nth-child(2){width: 100%;padding: 20upx 30upx 30upx;float: left;}
.list-date{width: calc((100% - 30px) / 7);height: 58px;border-radius: 10upx;float: left;display: flex;align-items: center;justify-content: center;
margin-left: 5px;margin-top: 5px;}
.list-date{font-size: 30upx;color: #252525;}
.list-time>view:nth-child(2)>view:nth-child(7n+1){margin-left: 0 !important;}
.list-cur-one{background-color: #F8C691;}
.list-cur-two{background-color: #FC9C39;}
.list-cur-two>view>view:nth-child(1){color: #252525 !important;}
.reser-cur-font{font-size: 24upx;color: #FFFFFF;}
.reser-hui{color: #AAAAAA;}
.reser-chen{color: #FC9C39;}
</style>
需要引入的.vue
<template>
<view>
<view @click="page_showModal('reservation',1)">打开房租</view>
<view @click="page_showModal('reservation',2)">打开日历</view>
<page-reservation v-if="page_modalName" :modalName="page_modalName" :ReserVation="ReserVation" @showModal="page_showModal"
@getHotelData="getHotelData"></page-reservation>
</view>
</template>
<script>
import PageReservation from '@/colorui/components/page-reservation.vue'
export default {
components:{ PageReservation },
data() {
return {
page_modalName:'',
ReserVation:uni.getStorageSync('ReserVation'),//入住人数日期
}
},
methods: {
// 修改入住信息
getHotelData(peopleArr,InCheckin,IntimeCur){
this.ReserVation.peopleArr = peopleArr
this.ReserVation.InCheckin = InCheckin
this.ReserVation.IntimeCur = IntimeCur
uni.setStorage({key:"ReserVation",data:this.ReserVation})
this.page_showModal('')
},
// 入住信息弹窗
page_showModal(target,type){
var that = this
if(type){
that.ReserVation.reservType = type
}
that.page_modalName = '1'
setTimeout(() => {
that.page_modalName = target
},target?100:500)
},
},
</script>
默认选择当天和明天
入住一次性最多选择三十天
默认获取三个月日期数组
存储信息
InCheckin 选择的日期信息
IntimeCur 组件选择的日期
peopleArr 入住人数信息
timeDataArr 显示的日历
引入的组件库ColorUI组件库
用的是uni-app
遇到问题可以看我主页加我Q,很少看博客,对你有帮助别忘记点赞收藏。