uni-app跳转到详情页面

通过使用uni.navigateTo()传值给详情页

详情页通过onLoad()进行接收

index.vue 主要部分代码

<template>
	<view class="content">
		<view class="title_tag">
			<text class="title">场所预定</text>
			<navigator class="text_right" url="/pages/pleace/pleace" open-type="navigate">更多 > </navigator>
		</view>
		<view class="card reserve_content" v-for="reserve in reserveList" :key="reserve.id">
			<view @click="toDetail(reserve.pleace_id)">
				<view class="reserve_title">
					<text>{{reserve.title}}</text>
					<text :class="[reserve.isCrawd ? 'crowd_off' : 'crowd_on']" style="width: 10rpx; height: 10rpx; margin: 18rpx 10rpx 0 0; border-radius: 10rpx; float:right;"></text>
				</view>
				<view class="reserve_desc">
					<text><text class="reserve_label">开放时间:</text>{{reserve.time}}</text>
					<text><text class="reserve_label">当前人数:</text> {{reserve.current}}/{{reserve.total}}人</text>
				</view>
			</view>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				reserveList:[
					{
						pleace_id: 1,
						title: "教学楼A-413",
						time: "24小时",
						current: 10,
						total: 30,
						isCrawd: true,
					},
					{
						pleace_id: 2,
						title: "教学楼A-414",
						time: "16:00-20:00",
						current: 10,
						total: 30,
						isCrawd: false,
					},{
						pleace_id: 3,
						title: "教学楼A-415",
						time: "17:00-20:00",
						current: 10,
						total: 30,
						isCrawd: true,
					}
				]
			}
		},
		methods: {
			toDetail(pleaceId){
				// this.$emit("toDetail", pleaceId);
				// alert(pleaceId);
				uni.navigateTo({
					url: '/pages/pleace/detail/pleaceDetail?pleaceId=' + pleaceId
				})
			}
		}
	}
</script>

 pleaceDetail.vue 主要部分代码

<template>
	<view class="content">
	</view>
</template>

<script>
	export default {
		onLoad(option){
			alert(option.pleaceId)
		}
	}
</script>

全部代码

index.vue

<template>
	<view class="content">
		<view class="header">
			<swiper circular  indicator-color="white" indicator-active-color="white" autoplay interval="3000">
				<swiper-item v-for="item in swipers" class="swiper-item">
					<image :src="item"></image>
				</swiper-item>
			</swiper>
		</view>
		
		<view class="card">
			<view class="button-code" hover-class="button-hover" @tap="handleClick()">
				<view class="code_content">
					<image src="../../static/images/iconfont.png"/>
					<text>健康码</text>
				</view>
			</view>
			<view class="btn-list">
				<view class="btn-item">
					<navigator url="/pages/health/health" open-type="navigate">健康上报</navigator>
				</view>
				<view class="btn-item">
					<navigator url="/pages/fever/fever" open-type="navigate">发热上报</navigator>
				</view>
			</view>
		</view>
		<view class="title_tag">
			<text class="title">场所预定</text>
			<navigator class="text_right" url="/pages/pleace/pleace" open-type="navigate">更多 > </navigator>
		</view>
		<view class="card reserve_content" v-for="reserve in reserveList" :key="reserve.id">
			<view @click="toDetail(reserve.pleace_id)">
				<view class="reserve_title">
					<text>{{reserve.title}}</text>
					<text :class="[reserve.isCrawd ? 'crowd_off' : 'crowd_on']" style="width: 10rpx; height: 10rpx; margin: 18rpx 10rpx 0 0; border-radius: 10rpx; float:right;"></text>
				</view>
				<view class="reserve_desc">
					<text><text class="reserve_label">开放时间:</text>{{reserve.time}}</text>
					<text><text class="reserve_label">当前人数:</text> {{reserve.current}}/{{reserve.total}}人</text>
				</view>
			</view>
		</view>
	
		
		<view class="footer">
			<text>快疫通提供技术支持</text>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				swipers:[
					'http://www.greathiit.com/uploadfile/2020/1224/20201224094242158.jpg',
					'http://www.greathiit.com/uploadfile/2020/1223/20201223034132864.jpg',
					'http://www.greathiit.com/uploadfile/2020/1223/20201223033927606.jpg',
				],
				reserveList:[
					{
						pleace_id: 1,
						title: "教学楼A-413",
						time: "24小时",
						current: 10,
						total: 30,
						isCrawd: true,
					},
					{
						pleace_id: 2,
						title: "教学楼A-414",
						time: "16:00-20:00",
						current: 10,
						total: 30,
						isCrawd: false,
					},{
						pleace_id: 3,
						title: "教学楼A-415",
						time: "17:00-20:00",
						current: 10,
						total: 30,
						isCrawd: true,
					}
				]
			}
		},
		methods: {
			handleClick(val){
			    uni.scanCode({
					onlyFromCamera:true,
			    	success: (res) => {
			    		console.log(JSON.parse(res.result));
			    		this.msg = res.result
			    	}
			    })
			},
			toPage(val){
				
			},
			toDetail(pleaceId){
				uni.navigateTo({
					url: '/pages/pleace/detail/pleaceDetail?pleaceId=' + pleaceId
				})
			}
		},
		onLoad(){
			
		}
	}
</script>

<style lang="scss" scoped>
	  .content {
		display: flex;
		flex-direction: column;
		justify-content: center;
		background-color: #ffffff;
		
		.title_tag{
			width: 650rpx;
			height: 30rpx;
			line-height: 30rpx;
			padding-left: 10rpx;
			border-left: 3px solid #2a80f3;
			margin-top: 40rpx;
			margin-left: auto;
			margin-right: auto;
			
			.title{
				font-size: 35rpx;
				font-weight: bold;
			}
			
			.text_right{
				width: 100rpx;
				font-size: 30rpx;
				color: #9a9a9a;
				float: right;
			}
		}
	  }
	  
	  .header {
		width: 100%;
		height: 300rpx;
		margin: 0 auto;
		
		image {
		  width: 100%;
		  height: 300rpx;
		}
		
		.swiper-item{
			position: inherit;
		}
	  }
	.button-code {
		color: #000;
		font-size: 34rpx;
		width: 620rpx;
		height: 130rpx;
		background-color: #ffffff;
		box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
		border-radius: 14rpx;
		line-height: 130rpx;
		text-align: center;
		margin-left: auto;
		margin-right: auto;
		position: relative;
		// margin-top: auto;
		.code_content{
			padding-left: 90rpx;
		}
		image{
			width: 60rpx;
			height: 60rpx;
			position: absolute;
			left: 30%;
			top: 30%;
		}
	}
	
	.card{
		width: 640rpx;
		height: 260rpx;
		background-color: #fefeff;
		border-radius: 14rpx;
		z-index: 600;
		padding: 35rpx 15rpx;
		// margin-top: 100rpx;
		margin-top: -40rpx;
		margin-left: auto;
		margin-right: auto;
		
		.title{
			font-size: 50rpx;
			font-weight: 400;
		}
		.btn-list{
			display: flex;
			margin-top: 50rpx;
			.btn-item{
				width: 290rpx;
				height: 80rpx;
				border: none;
				background-color: #fffffe;
				border: 1px solid #ededf1;
				// box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
				border-radius: 14rpx;
				text-align: center;
				line-height: 80rpx;
			}
			.btn-item:nth-child(2){
				margin-left: 60rpx;
			}
		}
	}
	.reserve_content{
		height: 160rpx;
		padding: 20rpx 25rpx;
		margin-top: 20rpx;
		// border: 1px solid #ededf1;
		box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
		background-color: #FFF;
		
		
		.crowd_off{
			background-color: red;
		}
		 
		 .crowd_on{
			 background: green;
		 }
		
		.reserve_title{
			font-size: 30rpx;
			padding-bottom: 15rpx;
			border-bottom: 2rpx solid #e1e1e1;
		}
		
		.reserve_desc{
			margin-top: 20rpx;
			
			text{
				display: block;
				font-size: 25rpx;
				line-height: 40rpx;
				.reserve_label{
					display: inline;
					color: #a4a4a4;
					margin-right: 20rpx;
				}
			}
		}
	}
	.footer{
		width: 620rpx;
		height: 200rpx;
		text-align: center;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
	}
	
	.footer text{
		font-size: 28rpx;
		color: #c8c8c9;
	}
</style>

pleaceDetail.vue

<template>
	<view class="content">
		<view class="header">
			<swiper circular  indicator-color="white" indicator-active-color="white" autoplay interval="3000">
				<swiper-item v-for="item in swipers" class="swiper-item">
					<image :src="item"></image>
				</swiper-item>
			</swiper>
		</view>
		
		<view class="card">
			<view class="button-code" hover-class="button-hover" @tap="handleClick()">
				<view class="code_content">
					<image src="../../static/images/iconfont.png"/>
					<text>健康码</text>
				</view>
			</view>
			<view class="btn-list">
				<view class="btn-item">
					<navigator url="/pages/health/health" open-type="navigate">健康上报</navigator>
				</view>
				<view class="btn-item">
					<navigator url="/pages/fever/fever" open-type="navigate">发热上报</navigator>
				</view>
			</view>
		</view>
		<view class="title_tag">
			<text class="title">场所预定</text>
			<navigator class="text_right" url="/pages/pleace/pleace" open-type="navigate">更多 > </navigator>
		</view>
		<view class="card reserve_content" v-for="reserve in reserveList" :key="reserve.id">
			<view @click="toDetail(reserve.pleace_id)">
				<view class="reserve_title">
					<text>{{reserve.title}}</text>
					<text :class="[reserve.isCrawd ? 'crowd_off' : 'crowd_on']" style="width: 10rpx; height: 10rpx; margin: 18rpx 10rpx 0 0; border-radius: 10rpx; float:right;"></text>
				</view>
				<view class="reserve_desc">
					<text><text class="reserve_label">开放时间:</text>{{reserve.time}}</text>
					<text><text class="reserve_label">当前人数:</text> {{reserve.current}}/{{reserve.total}}人</text>
				</view>
			</view>
		</view>
	
		
		<view class="footer">
			<text>快疫通提供技术支持</text>
		</view>
	</view>
</template>

<script>
	export default {
		data() {
			return {
				swipers:[
					'http://www.greathiit.com/uploadfile/2020/1224/20201224094242158.jpg',
					'http://www.greathiit.com/uploadfile/2020/1223/20201223034132864.jpg',
					'http://www.greathiit.com/uploadfile/2020/1223/20201223033927606.jpg',
				],
				reserveList:[
					{
						pleace_id: 1,
						title: "教学楼A-413",
						time: "24小时",
						current: 10,
						total: 30,
						isCrawd: true,
					},
					{
						pleace_id: 2,
						title: "教学楼A-414",
						time: "16:00-20:00",
						current: 10,
						total: 30,
						isCrawd: false,
					},{
						pleace_id: 3,
						title: "教学楼A-415",
						time: "17:00-20:00",
						current: 10,
						total: 30,
						isCrawd: true,
					}
				]
			}
		},
		methods: {
			handleClick(val){
			    uni.scanCode({
					onlyFromCamera:true,
			    	success: (res) => {
			    		console.log(JSON.parse(res.result));
			    		this.msg = res.result
			    	}
			    })
			},
			toPage(val){
				
			},
			toDetail(pleaceId){
				// this.$emit("toDetail", pleaceId);
				// alert(pleaceId);
				uni.navigateTo({
					url: '/pages/pleace/detail/pleaceDetail?pleaceId=' + pleaceId
				})
			}
		},
		onLoad(){
			
		}
	}
</script>

<style lang="scss" scoped>
	  .content {
		display: flex;
		flex-direction: column;
		justify-content: center;
		background-color: #ffffff;
		
		.title_tag{
			width: 650rpx;
			height: 30rpx;
			line-height: 30rpx;
			padding-left: 10rpx;
			border-left: 3px solid #2a80f3;
			margin-top: 40rpx;
			margin-left: auto;
			margin-right: auto;
			
			.title{
				font-size: 35rpx;
				font-weight: bold;
			}
			
			.text_right{
				width: 100rpx;
				font-size: 30rpx;
				color: #9a9a9a;
				float: right;
			}
		}
	  }
	  
	  .header {
		width: 100%;
		height: 300rpx;
		margin: 0 auto;
		
		image {
		  width: 100%;
		  height: 300rpx;
		}
		
		.swiper-item{
			position: inherit;
		}
	  }
	.button-code {
		color: #000;
		font-size: 34rpx;
		width: 620rpx;
		height: 130rpx;
		background-color: #ffffff;
		box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
		border-radius: 14rpx;
		line-height: 130rpx;
		text-align: center;
		margin-left: auto;
		margin-right: auto;
		position: relative;
		// margin-top: auto;
		.code_content{
			padding-left: 90rpx;
		}
		image{
			width: 60rpx;
			height: 60rpx;
			position: absolute;
			left: 30%;
			top: 30%;
		}
	}
	
	.card{
		width: 640rpx;
		height: 260rpx;
		background-color: #fefeff;
		border-radius: 14rpx;
		z-index: 600;
		padding: 35rpx 15rpx;
		// margin-top: 100rpx;
		margin-top: -40rpx;
		margin-left: auto;
		margin-right: auto;
		
		.title{
			font-size: 50rpx;
			font-weight: 400;
		}
		.btn-list{
			display: flex;
			margin-top: 50rpx;
			.btn-item{
				width: 290rpx;
				height: 80rpx;
				border: none;
				background-color: #fffffe;
				border: 1px solid #ededf1;
				// box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
				border-radius: 14rpx;
				text-align: center;
				line-height: 80rpx;
			}
			.btn-item:nth-child(2){
				margin-left: 60rpx;
			}
		}
	}
	.reserve_content{
		height: 160rpx;
		padding: 20rpx 25rpx;
		margin-top: 20rpx;
		// border: 1px solid #ededf1;
		box-shadow: 1rpx 0rpx 15rpx 5rpx #ededf1;
		background-color: #FFF;
		
		
		.crowd_off{
			background-color: red;
		}
		 
		 .crowd_on{
			 background: green;
		 }
		
		.reserve_title{
			font-size: 30rpx;
			padding-bottom: 15rpx;
			border-bottom: 2rpx solid #e1e1e1;
		}
		
		.reserve_desc{
			margin-top: 20rpx;
			
			text{
				display: block;
				font-size: 25rpx;
				line-height: 40rpx;
				.reserve_label{
					display: inline;
					color: #a4a4a4;
					margin-right: 20rpx;
				}
			}
		}
	}
	.footer{
		width: 620rpx;
		height: 200rpx;
		text-align: center;
		margin-top: 200rpx;
		margin-left: auto;
		margin-right: auto;
	}
	
	.footer text{
		font-size: 28rpx;
		color: #c8c8c9;
	}
</style>

这里pleaceDetail.vue中用到了一个时间的组件,为了避免你报错,我把它放在下面

请在components/mx-datepicker/ 下创建mx-datepicker.vue

代码

<template>
    <view v-if="isShow" class="picker">
        <!-- 日期选择器 -->
        <view v-if="type!='time'" class="picker-modal">
            <view class="picker-modal-header">
                <view class="picker-icon picker-icon-zuozuo" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('-1')"></view>
                <view class="picker-icon picker-icon-zuo" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('-1')"></view>
                <text class="picker-modal-header-title">{{title}}</text>
                <view class="picker-icon picker-icon-you" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetMonth('+1')"></view>
                <view class="picker-icon picker-icon-youyou" :hover-stay-time="100" hover-class="picker-icon-active" @click="onSetYear('+1')"></view>
            </view>
            <swiper class="picker-modal-body" :circular="true" :duration="200" :skip-hidden-item-layout="true" :current="calendarIndex" @change="onSwiperChange">
                <swiper-item class="picker-calendar" v-for="(calendar,calendarIndex2) in calendars" :key="calendarIndex2">
                    <view class="picker-calendar-view" v-for="(week,index) in weeks" :key="index - 7">
                        <view class="picker-calendar-view-item">{{week}}</view>
                    </view>
                    <view class="picker-calendar-view" v-for="(date,dateIndex) in calendar" :key="dateIndex" @click="onSelectDate(date)">
                        <!-- 背景样式 -->
                        <view v-show="date.bgStyle.type" :class="'picker-calendar-view-'+date.bgStyle.type" :style="{background: date.bgStyle.background}"></view>
                        <!-- 正常和选中样式 -->
                        <view class="picker-calendar-view-item" :style="{opacity: date.statusStyle.opacity, color: date.statusStyle.color, background: date.statusStyle.background}">
                            <text>{{date.title}}</text>
                        </view>
                        <!-- 小圆点样式 -->
                        <view class="picker-calendar-view-dot" :style="{opacity: date.dotStyle.opacity, background: date.dotStyle.background}"></view>
                        <!-- 信息样式 -->
                        <view v-show="date.tips" class="picker-calendar-view-tips">{{date.tips}}</view>
                    </view>
                </swiper-item>
            </swiper>
            <view class="picker-modal-footer">
                <view class="picker-modal-footer-info">
                    <block v-if="isMultiSelect">
                        <view class="picker-display">
                            <text>{{beginText}}日期</text>
                            <text class="picker-display-text">{{BeginTitle}}</text>
                            <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
                             :style="{color}" @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
                        </view>
                        <view class="picker-display">
                            <text>{{endText}}日期</text>
                            <text class="picker-display-text">{{EndTitle}}</text>
                            <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
                             :style="{color}" @click="onShowTimePicker('end')">{{EndTimeTitle}}</view>
                        </view>
                    </block>
                    <block v-else>
                        <view class="picker-display">
                            <text>当前选择</text>
                            <text class="picker-display-text">{{BeginTitle}}</text>
                            <view v-if="isContainTime" class="picker-display-link" :hover-stay-time="100" hover-class="picker-display-link-active"
                             :style="{color}" @click="onShowTimePicker('begin')">{{BeginTimeTitle}}</view>
                        </view>
                    </block>
                </view>
                <view class="picker-modal-footer-btn">
                    <view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click="onCancel">取消</view>
                    <view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click="onConfirm">确定</view>
                </view>
            </view>
        </view>
        <!-- 时间选择器 -->
        <view v-if="showTimePicker" class="picker">
            <view class="picker-modal picker-time">
                <view class="picker-modal-header">
                    <text class="picker-modal-header-title">选择日期</text>
                </view>
                <picker-view class="picker-modal-time" indicator-class="picker-modal-time-item" :value="timeValue" @change="onTimeChange">
                    <picker-view-column>
                        <view v-for="(v,i) in 24" :key="i">{{i<10?'0'+i:i}}时</view>
                    </picker-view-column>
                    <picker-view-column>
                        <view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}分</view>
                    </picker-view-column>
                    <picker-view-column v-if="showSeconds">
                        <view v-for="(v,i) in 60" :key="i">{{i<10?'0'+i:i}}秒</view>
                    </picker-view-column>
                </picker-view>
                <view class="picker-modal-footer">
                    <view class="picker-modal-footer-info">
                        <view class="picker-display">
                            <text>当前选择</text>
                            <text class="picker-display-text">{{PickerTimeTitle}}</text>
                        </view>
                    </view>
                    <view class="picker-modal-footer-btn">
                        <view class="picker-btn" :hover-stay-time="100" hover-class="picker-btn-active" @click="onCancelTime">取消</view>
                        <view class="picker-btn" :style="{color}" :hover-stay-time="100" hover-class="picker-btn-active" @click="onConfirmTime">确定</view>
                    </view>
                </view>
            </view>
        </view>
    </view>
</template>

<script>
    /**
     * 工具函数库
     */
    const DateTools = {
        /**
         * 获取公历节日
         * @param date Date对象
         */
        getHoliday(date) {
            let holidays = {
                '0101': '元旦',
                '0214': '情人',
                '0308': '妇女',
                '0312': '植树',
                '0401': '愚人',
                '0501': '劳动',
                '0504': '青年',
                '0601': '儿童',
                '0701': '建党',
                '0801': '建军',
                '0903': '抗日',
                '0910': '教师',
                '1001': '国庆',
                '1031': '万圣',
                '1224': '平安',
                '1225': '圣诞'
            };
            let value = this.format(date, 'mmdd');
            if (holidays[value]) return holidays[value];
            return false;
        },
        /**
         * 解析标准日期格式
         * @param s 日期字符串
         * @return 返回Date对象
         */
        parse: s => new Date(s.replace(/(年|月|-)/g, '/').replace(/(日)/g, '')),
        /**
         * 比较日期是否为同一天
         * @param a Date对象
         * @param b Date对象
         * @return Boolean
         */
        isSameDay: (a, b) => a.getMonth() == b.getMonth() && a.getFullYear() == b.getFullYear() && a.getDate() == b.getDate(),
        /**
         * 格式化Date对象
         * @param d 日期对象
         * @param f 格式字符串
         * @return 返回格式化后的字符串
         */
        format(d, f) {
            var o = {
                "m+": d.getMonth() + 1,
                "d+": d.getDate(),
                "h+": d.getHours(),
                "i+": d.getMinutes(),
                "s+": d.getSeconds(),
                "q+": Math.floor((d.getMonth() + 3) / 3),
            };
            if (/(y+)/.test(f))
                f = f.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
            for (var k in o)
                if (new RegExp("(" + k + ")").test(f))
                    f = f.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            return f;
        },
        /**
         * 用于format格式化后的反解析
         * @param s 日期字符串
         * @param f 格式字符串
         * @return 返回Date对象
         */
        inverse(s, f) {
            var o = {
                "y": '',
                "m": '',
                "d": '',
                "h": '',
                "i": '',
                "s": '',
            };
            let d = new Date();
            if (s.length != f.length) return d;
            for (let i in f)
                if (o[f[i]] != undefined) o[f[i]] += s[i];
            if (o.y) d.setFullYear(o.y.length < 4 ? (d.getFullYear() + '').substr(0, 4 - o.y.length) + o.y : o.y);
            o.m && d.setMonth(o.m - 1, 1);
            o.d && d.setDate(o.d - 0);
            o.h && d.setHours(o.h - 0);
            o.i && d.setMinutes(o.i - 0);
            o.s && d.setSeconds(o.s - 0);
            return d;
        },
        /**
         * 获取日历数组(42天)
         * @param date 日期对象或日期字符串
         * @param proc 处理日历(和forEach类似),传递一个数组中的item
         * @return Array
         */
        getCalendar(date, proc) {
            let it = new Date(date),
                calendars = [];
            it.setDate(1);
            it.setDate(it.getDate() - ((it.getDay() == 0 ? 7 : it.getDay()) - 1)); //偏移量
            for (let i = 0; i < 42; i++) {
                let tmp = {
                    dateObj: new Date(it),
                    title: it.getDate(),
                    isOtherMonth: it.getMonth() < date.getMonth() || it.getMonth() > date.getMonth()
                };
                calendars.push(Object.assign(tmp, proc ? proc(tmp) : {}));
                it.setDate(it.getDate() + 1);
            }
            return calendars;
        },
        /**
         * 获取日期到指定的月份1号(不改变原来的date对象)
         * @param d Date对象
         * @param v 指定的月份
         * @return Date对象
         */
        getDateToMonth(d, v) {
            let n = new Date(d);
            n.setMonth(v, 1);
            return n;
        },
        /**
         * 把时间数组转为时间字符串
         * @param t Array[时,分,秒]
         * @param showSecinds 是否显示秒
         * @return 字符串 时:分[:秒]
         */
        formatTimeArray(t, s) {
            let r = [...t];
            if (!s) r.length = 2;
            r.forEach((v, k) => r[k] = ('0' + v).slice(-2));
            return r.join(':');
        }
    };

    export default {
        props: {
            //颜色
            color: {
                type: String,
                default: '#409eff'
            },
            //是否显示秒 针对type为datetime或time时生效
            showSeconds: {
                type: Boolean,
                default: false
            },
            //初始的值
            value: [String, Array],
            //类型date time datetime range rangetime
            type: {
                type: String,
                default: 'range'
            },
            //是否显示
            show: {
                type: Boolean,
                default: false
            },
            //初始格式
            format: {
                type: String,
                default: ''
            },
            //显示公历节日
            showHoliday: {
                type: Boolean,
                default: true
            },
            //显示提示
            showTips: {
                type: Boolean,
                default: false
            },
            //开始文案 针对type为范围选择时生效
            beginText: {
                type: String,
                default: '开始'
            },
            //结束文案 针对type为范围选择时生效
            endText: {
                type: String,
                default: '结束'
            }
        },
        data() {
            return {
                isShow: false, //是否显示
                isMultiSelect: false, //是否为多选
                isContainTime: false, //是否包含时间
                date: {}, //当前日期对象
                weeks: ["一", "二", "三", "四", "五", "六", "日"],
                title: '初始化', //标题
                calendars: [[],[],[]], //日历数组
                calendarIndex: 1, //当前日历索引
                checkeds: [], //选中的日期对象集合
                showTimePicker: false, //是否显示时间选择器
                timeValue: [0, 0, 0], //时间选择器的值
                timeType: 'begin', //当前时间选择的类型
                beginTime: [0, 0, 0], //当前所选的开始时间值
                endTime: [0, 0, 0], //当前所选的结束时间值
            };
        },
        methods: {
            //设置值
            setValue(value) {
                this.date = new Date();
                this.checkeds = [];
                this.isMultiSelect = this.type.indexOf('range') >= 0;
                this.isContainTime = this.type.indexOf('time') >= 0;
                //将字符串解析为Date对象
                let parseDateStr = (str) => (this.format ? DateTools.inverse(str, this.format) : DateTools.parse(str));
                if (value) {
                    if (this.isMultiSelect) {
                        Array.isArray(value) && value.forEach((dateStr, index) => {
                            let date = parseDateStr(dateStr);
                            let time = [date.getHours(), date.getMinutes(), date.getSeconds()];
                            if (index == 0) this.beginTime = time;
                            else this.endTime = time;
                            this.checkeds.push(date);
                        });
                    } else {
                        if (this.type == 'time') {
                            let date = parseDateStr('2019/1/1 ' + value);
                            this.beginTime = [date.getHours(), date.getMinutes(), date.getSeconds()];
                            this.onShowTimePicker('begin');
                        } else {
                            this.checkeds.push(parseDateStr(value));
                            if (this.isContainTime) this.beginTime = [
                                this.checkeds[0].getHours(),
                                this.checkeds[0].getMinutes(),
                                this.checkeds[0].getSeconds()
                            ];
                        }
                    }
                    if (this.checkeds.length) this.date = new Date(this.checkeds[0]);
                } else {
                    if (this.isContainTime) {
                        this.beginTime = [this.date.getHours(), this.date.getMinutes(), this.date.getSeconds()];
                        if (this.isMultiSelect) this.endTime = [...this.beginTime];
                    }
                    this.checkeds.push(new Date(this.date));
                }
                if (this.type != 'time') this.refreshCalendars(true);
                else this.onShowTimePicker('begin');
            },
            //改变年份
            onSetYear(value) {
                this.date.setFullYear(this.date.getFullYear() + parseInt(value));
                this.refreshCalendars(true);
            },
            //改变月份
            onSetMonth(value) {
                this.date.setMonth(this.date.getMonth() + parseInt(value));
                this.refreshCalendars(true);
            },
            //时间选择变更
            onTimeChange(e) {
                this.timeValue = e.detail.value;
            },
            //设置时间选择器的显示状态
            onShowTimePicker(type) {
                this.showTimePicker = true;
                this.timeType = type;
                this.timeValue = type == 'begin' ? [...this.beginTime] : [...this.endTime];
            },
            //处理日历
            procCalendar(item) {
                //定义初始样式
                item.statusStyle = {
                    opacity: 1,
                    color: item.isOtherMonth ? '#ddd' : '#000',
                    background: 'transparent'
                };
                item.bgStyle = {
                    type: '',
                    background: 'transparent'
                };
                item.dotStyle = {
                    opacity: 1,
                    background: 'transparent'
                };
                item.tips = "";
                //标记今天的日期
                if (DateTools.isSameDay(new Date(), item.dateObj)) {
                    item.statusStyle.color = this.color;
                    if (item.isOtherMonth) item.statusStyle.opacity = 0.3;
                }
                //标记选中项
                this.checkeds.forEach(date => {
                    if (DateTools.isSameDay(date, item.dateObj)) {
                        item.statusStyle.background = this.color;
                        item.statusStyle.color = '#fff';
                        item.statusStyle.opacity = 1;
                        if (this.isMultiSelect && this.showTips) item.tips = this.beginText;
                    }
                });
                //节假日或今日的日期标点
                if (item.statusStyle.background != this.color) {
                    let holiday = this.showHoliday ? DateTools.getHoliday(item.dateObj) : false;
                    if (holiday || DateTools.isSameDay(new Date(), item.dateObj)) {
                        item.title = holiday || item.title;
                        item.dotStyle.background = this.color;
                        if (item.isOtherMonth) item.dotStyle.opacity = 0.2;
                    }
                } else {
                    item.title = item.dateObj.getDate();
                }
                //有两个日期
                if (this.checkeds.length == 2) {
                    if (DateTools.isSameDay(this.checkeds[0], item.dateObj)) { //开始日期
                        item.bgStyle.type = 'bgbegin';
                    }
                    if (DateTools.isSameDay(this.checkeds[1], item.dateObj)) { //结束日期
                        if (this.isMultiSelect && this.showTips) item.tips = item.bgStyle.type ? this.beginText + ' / ' + this.endText : this.endText;
                        if (!item.bgStyle.type) { //开始日期不等于结束日期
                            item.bgStyle.type = 'bgend';
                        } else {
                            item.bgStyle.type = '';
                        }
                    }
                    if (!item.bgStyle.type && (+item.dateObj > +this.checkeds[0] && +item.dateObj < +this.checkeds[1])) { //中间的日期
                        item.bgStyle.type = 'bg';
                        item.statusStyle.color = this.color;
                    }
                    if (item.bgStyle.type) {
                        item.bgStyle.background = this.color;
                        item.dotStyle.opacity = 1;
                        item.statusStyle.opacity = 1;
                    }
                }
            },
            //刷新日历
            refreshCalendars(refresh = false) {
                let date = new Date(this.date);
                let before = DateTools.getDateToMonth(date, date.getMonth() - 1);
                let after = DateTools.getDateToMonth(date, date.getMonth() + 1);
                if (this.calendarIndex == 0) {
                    if(refresh) this.calendars.splice(0, 1, DateTools.getCalendar(date, this.procCalendar));
                    this.calendars.splice(1, 1, DateTools.getCalendar(after, this.procCalendar));
                    this.calendars.splice(2, 1, DateTools.getCalendar(before, this.procCalendar));
                } else if (this.calendarIndex == 1) {
                    this.calendars.splice(0, 1, DateTools.getCalendar(before, this.procCalendar));
                    if(refresh) this.calendars.splice(1, 1, DateTools.getCalendar(date, this.procCalendar));
                    this.calendars.splice(2, 1, DateTools.getCalendar(after, this.procCalendar));
                } else if (this.calendarIndex == 2) {
                    this.calendars.splice(0, 1, DateTools.getCalendar(after, this.procCalendar));
                    this.calendars.splice(1, 1, DateTools.getCalendar(before, this.procCalendar));
                    if(refresh) this.calendars.splice(2, 1, DateTools.getCalendar(date, this.procCalendar));
                }
                this.title = DateTools.format(this.date, 'yyyy年mm月');
            },
            //滑块切换
            onSwiperChange(e) {
                this.calendarIndex = e.detail.current;
                let calendar = this.calendars[this.calendarIndex];
                this.date = new Date(calendar[22].dateObj); //取中间一天,保证是当前的月份
                this.refreshCalendars();
            },
            //选中日期
            onSelectDate(date) {
                if (~this.type.indexOf('range') && this.checkeds.length == 2) this.checkeds = [];
                else if (!(~this.type.indexOf('range')) && this.checkeds.length) this.checkeds = [];
                this.checkeds.push(new Date(date.dateObj));
                this.checkeds.sort((a, b) => a - b); //从小到大排序
                this.calendars.forEach(calendar => {
                    calendar.forEach(this.procCalendar); //重新处理
                });
            },
            //时间选择取消
            onCancelTime() {
                this.showTimePicker = false;
                this.type == 'time' && this.onCancel();
            },
            //时间选择确定
            onConfirmTime() {
                if (this.timeType == 'begin') this.beginTime = this.timeValue;
                else this.endTime = this.timeValue;
                this.showTimePicker = false;
                this.type == 'time' && this.onConfirm();
            },
            //取消
            onCancel() {
                this.$emit('cancel', false);
            },
            //确定
            onConfirm() {
                let result = {
                    value: null,
                    date: null
                };
                //定义默认格式
                let defaultFormat = {
                    'date': 'yyyy/mm/dd',
                    'time': 'hh:ii' + (this.showSeconds ? ':ss' : ''),
                    'datetime': ''
                };
                defaultFormat['datetime'] = defaultFormat.date + ' ' + defaultFormat.time;
                let fillTime = (date, timeArr) => {
                    date.setHours(timeArr[0], timeArr[1]);
                    if (this.showSeconds) date.setSeconds(timeArr[2]);
                };
                if (this.type == 'time') {
                    let date = new Date();
                    fillTime(date, this.beginTime);
                    result.value = DateTools.format(date, this.format ? this.format : defaultFormat.time);
                    result.date = date;
                } else {
                    if (this.isMultiSelect) {
                        let values = [],
                            dates = [];
                        if (this.checkeds.length < 2) return uni.showToast({
                            icon: 'none',
                            title: '请选择两个日期'
                        });
                        this.checkeds.forEach((date, index) => {
                            let newDate = new Date(date);
                            if (this.isContainTime) {
                                let time = [this.beginTime, this.endTime];
                                fillTime(newDate, time[index]);
                            }
                            values.push(DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
                                'datetime' : 'date']));
                            dates.push(newDate);
                        });
                        result.value = values;
                        result.date = dates;
                    } else {
                        let newDate = new Date(this.checkeds[0]);
                        if (this.isContainTime) {
                            newDate.setHours(this.beginTime[0], this.beginTime[1]);
                            if (this.showSeconds) newDate.setSeconds(this.beginTime[2]);
                        }
                        result.value = DateTools.format(newDate, this.format ? this.format : defaultFormat[this.isContainTime ?
                            'datetime' : 'date']);
                        result.date = newDate;
                    }
                }
                this.$emit('confirm', result);
            }
        },
        computed: {
            BeginTitle() {
                let value = '未选择';
                if (this.checkeds.length) value = DateTools.format(this.checkeds[0], 'yy/mm/dd');
                return value;
            },
            EndTitle() {
                let value = '未选择';
                if (this.checkeds.length == 2) value = DateTools.format(this.checkeds[1], 'yy/mm/dd');
                return value;
            },
            PickerTimeTitle() {
                return DateTools.formatTimeArray(this.timeValue, this.showSeconds);
            },
            BeginTimeTitle() {
                return this.BeginTitle != '未选择' ? DateTools.formatTimeArray(this.beginTime, this.showSeconds) : '';
            },
            EndTimeTitle() {
                return this.EndTitle != '未选择' ? DateTools.formatTimeArray(this.endTime, this.showSeconds) : '';
            }
        },
        watch: {
            show(newValue, oldValue) {
                newValue && this.setValue(this.value);
                this.isShow = newValue;
            },
            value(newValue, oldValue) {
                setTimeout(()=>{
                    this.setValue(newValue);
                }, 0);
            }
        }
    }
</script>

<style lang="scss" scoped>
    $z-index: 100;
    $cell-spacing: 20upx;
    $calendar-size: 630upx;
    $calendar-item-size: 90upx;

    .picker {
        position: fixed;
        z-index: $z-index;
        background: rgba(255, 255, 255, 0);
        left: 0;
        top: 0;
        width: 100%;
        height: 100%;
        font-size: 28upx;

        &-btn {
            padding: $cell-spacing*0.5 $cell-spacing;
            border-radius: 12upx;
            color: #666;

            &-active {
                background: rgba(0, 0, 0, .1);
            }
        }

        &-display {
            color: #666;

            &-text {
                color: #000;
                margin: 0 $cell-spacing*0.5;
            }

            &-link {
                display: inline-block;

                &-active {
                    background: rgba(0, 0, 0, .1);
                }
            }
        }

        &-time {
            width: $calendar-size - 80upx !important;
            left: ((750upx - $calendar-size) / 2 + 40upx) !important;
        }

        &-modal {
            background: #fff;
            position: absolute;
            top: 50%;
            left: (750upx - $calendar-size) / 2;
            width: $calendar-size;
            transform: translateY(-50%);
            box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.1);
            border-radius: 12upx;

            &-header {
                text-align: center;
                line-height: 80upx;
                font-size: 32upx;

                &-title {
                    display: inline-block;
                    width: 40%;
                }

                .picker-icon {
                    display: inline-block;
                    line-height: 50upx;
                    width: 50upx;
                    height: 50upx;
                    border-radius: 50upx;
                    text-align: center;
                    margin: 10upx;
                    background: #fff;
                    font-size: 36upx;

                    &-active {
                        background: rgba(0, 0, 0, .1);
                    }
                }
            }

            &-body {
                width: $calendar-size !important;
                height: $calendar-size !important;
                position: relative;
            }

            &-time {
                width: 100%;
                height: 180upx;
                text-align: center;
                line-height: 60upx;
            }

            &-footer {
                display: flex;
                justify-content: space-between;
                align-items: center;
                padding: $cell-spacing;

                &-info {
                    flex-grow: 1;
                }

                &-btn {
                    flex-shrink: 0;
                    display: flex;
                }
            }
        }

        &-calendar {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            flex-wrap: wrap;

            &-view {
                position: relative;
                width: $calendar-item-size;
                height: $calendar-item-size;
                text-align: center;

                &-bgbegin,
                &-bg,
                &-bgend,
                &-item,
                &-dot,
                &-tips {
                    position: absolute;
                    transition: .2s;
                }

                &-bgbegin,
                &-bg,
                &-bgend {
                    opacity: .15;
                    height: 80%;
                }

                &-bg {
                    left: 0;
                    top: 10%;
                    width: 100%;
                }

                &-bgbegin {
                    border-radius: $calendar-item-size 0 0 $calendar-item-size;
                    top: 10%;
                    left: 10%;
                    width: 90%;
                }

                &-bgend {
                    border-radius: 0 $calendar-item-size $calendar-item-size 0;
                    top: 10%;
                    left: 0%;
                    width: 90%;
                }

                &-item {
                    left: 5%;
                    top: 5%;
                    width: 90%;
                    height: 90%;
                    border-radius: $calendar-item-size;
                    display: flex;
                    align-items: center;
                    justify-content: center;
                }

                &-dot {
                    right: 10%;
                    top: 10%;
                    width: 12upx;
                    height: 12upx;
                    border-radius: 12upx;
                }

                &-tips {
                    bottom: 100%;
                    left: 50%;
                    transform: translateX(-50%);
                    background: #4E4B46;
                    color: #fff;
                    border-radius: 12upx;
                    padding: 10upx 20upx;
                    font-size: 24upx;
                    width: max-content;
                    margin-bottom: 5px;
                    pointer-events: none;

                    &:after {
                        content: "";
                        position: absolute;
                        top: 100%;
                        left: 50%;
                        transform: translateX(-50%);
                        width: 0;
                        height: 0;
                        border-style: solid;
                        border-width: 5px 5px 0 5px;
                        border-color: #4E4B46 transparent transparent transparent;
                    }
                }
            }
        }
    }

    @font-face {
        font-family: "mxdatepickericon";
        src: url('data:application/x-font-woff2;charset=utf-8;base64,d09GMgABAAAAAAMYAAsAAAAACBgAAALMAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHEIGVgCDIgqDRIJiATYCJAMUCwwABCAFhG0HSRvfBsg+QCa3noNAyAQ9w6GDvbwpNp2vloCyn8bD/x+y+/5qDhtj+T4eRVEcbsCoKMFASzCgLdDkmqYDwgxkWQ6YH5L/YnppOlLEjlnter43YRjU7M6vJ3iGADVAgJn5kqjv/wEii23T86UsAQT+04fV+o97VTMx4PPZt4DlorLXwIQiGMA5uhaVrBWqGHfQXcTEiE+PE+g2SUlxWlLVBHwUYFMgrgwSB3wstTKSGzqF1nOyiGeeOtNjV4An/vvxR58PSc3AzrMViyDvPo/7dVEUzn5GROfIWAcU4rLXfMFdhte56y4We9gGNEVIezkBOOaQXUrbTf/hJVkhGpDdCw7dSOEzByMEn3kIic98hMxnAfeFPKWCbjRcA148/HxhCEkaA94eGWFaGolsblpaWz8/Po2WVuNHh1fmBpZHIpqal9fOjizhTteY+RZ9rv02I/pq0W6QVH3pSncBz3m55r9ZIPycHfmenvxe4uyutIgfT5u4bgkDusl9gcF0rnfnz+b2NpSaQWBFeu8GIL1xQj5AH/6FAsEr/50F28e/gA9ny6KjLrxIp0TE+UucmQOl5AFNLXkzZufWamWHYEI39PEP2If97CMdm51N6DSmIekwAVmneXTBr0PVYx+aTgfQbU3p+R4jKHdRurBq0oEw6AKSfm+QDbpGF/w3VOP+oBnMHbqdx409FjP4RRHHkAj5IWgQiBUjHfMTuQ1Icpg5avI4sQVRu8EHdWptM1aKrIjuscfeL+kZwxBTYoElztOQ2UygjRIjEphaZsyWodHgvm9SC8QC/JygEA6DiCDeEMhAQFhhOpvxa/18A0TiYMahIy0L2hYIZWeYH9JR085Al4qts1re5St2/SR6DINBGEVYQCWOETHDMAHZ+pcZIQJGTV4RtMmg8UbhuWL1+VLLA2RFHYC71kiRo0SNpjwQh8pj2EFU3oTNmS1WqgIA') format('woff2');
    }

    .picker-icon {
        font-family: "mxdatepickericon" !important;
    }

    .picker-icon-you:before {
        content: "\e63e";
    }

    .picker-icon-zuo:before {
        content: "\e640";
    }

    .picker-icon-zuozuo:before {
        content: "\e641";
    }

    .picker-icon-youyou:before {
        content: "\e642";
    }
</style>

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序是我的命

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值