uniapp 仿美团选择预送达时间或指定时间组件(2)(完整版)

子组件
components/delivery-time-op.vue

html

<template>
	<view>
		<!-- 模态框 -->
		<view @click="Modal" :class="{mask:model}"></view>
		<!-- 弹窗主体 -->
		<view :style="{'height':barHidth + 'rpx'}" class="active" :class="{add:model}">
			<view class="title">{{title}} 
				<!-- <text @click="showModal">X</text> -->
			</view>
			<view class="cont" :style="{height: barHidth - 80 + 'rpx'}">
				<view class="day">
					<view 
					:class="index === isIndex ? 'active_copy' : ''" 
					v-for="(item,index) in content" 
					:key="index"
					@click="dataCallback(item,index)"
					>{{item.timezh}}</view>
				</view>

				<scroll-view class="content" :scroll-y="true" :scroll-top="scrollTop">
					<view class="appoint" 
					:class="index === Indexes ? 'longActive' : ''" 
					@click="timeCallback(item,index)"
					v-for="(item,index) in Days" 
					:key="index"
					>
						{{item.timestr}}
						<text :class="index === Indexes ? 'cuIcon-check' : ''"></text>
					</view>
				</scroll-view>
			</view>
		</view>

	</view>
</template>

js

<script>
	export default {
		props: {
			//控制弹窗的隐藏显示
			model: {
				type: Boolean,
				default: false
			},
			//弹窗标题
			title: {
				type: String,
				default: '弹窗测试'
			},
			//弹窗内容
			content: {
				type: Array,
				default: [{
					content: '我是弹窗内容'
				}]
			},
			//弹窗 窗口高度
			barHidth: {
				type: Number,
				default: 400
			},
			//点击模态框是否能关闭弹窗
			showYes: {
				type: Boolean,
				default: false
			}
		},
		data() {
			return {
				scrollTop: 0,
				isIndex: 0,
				Indexes: 0,
				Days: [],
			}
		},
		mounted(){
			// 初始化
			this.Days = this.content[0].timelist;
		},

		methods: {
			// 关闭窗口
			showModal() {
				this.$emit('close', false)
			},
			// 点击模态框关闭窗口
			Modal() {
				if (this.showYes) {
					this.$emit('close', false)
				}
			},
			//配送时间切换回顶
			gotop() {
				this.scrollTop = 1;
				this.$nextTick(function() {
					this.scrollTop = 0;
				});
			},

			//切换日期
			dataCallback(item,index) {
				this.isIndex = index;
				this.Days = this.content[index].timelist;
				this.Indexes = null;
				this.gotop();
				this.$emit('dataCallback', item, index)
			},

			//选择时间
			timeCallback(item,index) {
				this.Indexes = index;
				this.modalName = null;
				this.$emit('timeCallback', item, index)
			},
		}
	}
</script>

css

<style scoped>
	.mask {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background-color: #000;
		animation: getInto .5s 1;
		opacity: 0.5;
		z-index: 999;
	}


	@keyframes getInto {
		0% {
			opacity: 0;
		}

		100% {
			opacity: 0.5;
		}

	}

	.active {
		position: fixed;
		bottom: 0;
		left: 0;
		z-index: 1000;
		width: 100%;
		height: 400rpx;
		border-top-left-radius: 16rpx;
		border-top-right-radius: 16rpx;
		overflow: hidden;
		transform: translateY(100%);
		transition: .4s;
	}

	.add {
		transform: translateY(0);
	}


	.title {
		position: relative;
		text-align: center;
		background-color: #fff;
		padding: 20rpx 0;
		border-bottom: 2rpx solid #eee;
	}

	.title>text {
		position: absolute;
		right: 14rpx;
		width: 40rpx;
		height: 40prx;
		background-color: #ccc;
		color: #666;
		border-radius: 50%;
		font-size: 32rpx;
	}

	.cont {
		display: flex;
		background-color: #fff;
		overflow-y: scroll;
	}

	.day {
		flex: 2;
		background-color: #F3F4F5;
		border-right: 2rpx solid #f8f8f8;
		text-align: center;

	}

	.day view {
		padding: 30rpx 12rpx;
		font-size: 28rpx;
		box-sizing: border-box;
	}

	.content {
		flex: 4;
		font-size: 28rpx;
		border-bottom: 40rpx solid #fff;
		background-color: #fff;
	}

	.appoint {
		text-align: left;
		padding: 30rpx;
		border-bottom: 2rpx solid #f8f8f8;
	}


	.appoint text {
		margin-right: 30rpx;
	}

	.active_copy {
		position: relative;
		background-color: #fff;
		color: #000000;
		box-sizing: border-box;

	}

	.active_copy::after {
		content: '';
		width: 5rpx;
		height: 94rpx;
		background: #fff;
		position: absolute;
		top: 0;
		right: 0;

	}

	.longActive {
		color: #FF502F;
		display: flex;
		align-items: center;
		justify-content: space-between;
		font-size: 32rpx;
		font-weight: 500;
	}
	
	.cuIcon-check{
		width: 30rpx;
		height: 16rpx;
		border-bottom: 4rpx solid #FF502F;
		border-left: 4rpx solid #FF502F;
		transform: rotate(-45deg);
	}
</style>

父组件
html

<template>
  <view>
	   <view class="pinck-box">
		<view class="picker-up-title">取货时间</view>
		<view class="pick-item">
		  <view class="block-up-title">{{bhTxt}}</view>
		  <view class="block-up-time" @click="showModel">
			<text>{{chooseDay}} {{chooseTime}}</text>
			<uni-icons type="right" />
		  </view>
		</view>
	  </view>

	  
	  <deliveryTimeOp
	  	  v-if="content && content.length != 0" 
	  	  @dataCallback="dataCallback" 
	  	  @timeCallback="timeCallback" 
	  	  :model='model' 
	  	  :showYes="model" 
	  	  :content="content" 
	  	  :barHidth='600' 
	  	  title="选择取货时间"
	  >
	  </deliveryTimeOp>
  </view>
</template>

js

<script>
import deliveryTimeOp from './components/delivery-time-op.vue'
export default {
  components: {
    deliveryTimeOp,
  },
  data() {
    return {
		// 控制显示隐藏
		model: false,
		// 需要传递展示的日期时间数据
		content: [
			// {timezh: "",timeformatter: "", timelist: []},
		],
		chooseTime: '', // 时间
		chooseDay: '', //星期
      	chooseDate: '', // 年月日
      	bhTxt: '尽快取货', // 取货时间文字
		now: '', // 当前的时间
    }
  },
  mounted() {
    
  },
  methods: {
    // 时间
    getDliveryTime(){
		let today = '';
		let nextDay = '';
		let threeDay = '';
		let timeformatter = '';
		let deliveryTimeList = [];
		// 当前时间戳
    	let now = new Date();
    	// 获取星期
    	let week = now.getDay();
		// 获取年
    	let Y = now.getFullYear();
		// 获取月
    	let M = now.getMonth() + 1;
    	M = M < 10 ? "0" + M : M;
		// 获取日
    	let D = now.getDate();
    	switch(week){
    		case 0:
    			today = "今天(周日)";
    			nextDay = "明天(周一)";
    			threeDay = "后天(周二)";
    			break;
    		case 1:
    			today = "今天(周一)";
    			nextDay = "明天(周二)";
    			threeDay = "后天(周三)";
    			break;
    		case 2:
    			today = "今天(周二)";
    			nextDay = "明天(周三)";
    			threeDay = "后天(周四)";
    			break;
    		case 3:
    			today = "今天(周三)";
    			nextDay = "明天(周四)";
    			threeDay = "后天(周五)";
    			break;
    		case 4:
    			today = "今天(周四)";
    			nextDay = "明天(周五)";
    			threeDay = "后天(周六)";
    			break;
    		case 5:
    			today = "今天(周五)";
    			nextDay = "明天(周六)";
    			threeDay = "后天(周日)";
    			break;
    		case 6:
    			today = "今天(周六)";
    			nextDay = "明天(周日)";
    			threeDay = "后天(周一)";
    			break;
    	}
    	
		// 判断是否是20点以后, 20点以后则默认值为第二天第一个
		let endTimeStamp = new Date(new Date().setHours(20)).getTime()
		let nowStamp = new Date().getTime()
		
    	if(nowStamp > endTimeStamp) {
    		let todayStr = this.getTimeList('two');
    		let nowDayList = this.getTimeObj(todayStr)
    		let D1 = new Date(new Date().setDate(new Date().getDate() + 1)).getDate().toString()
    		
    		let todayYMD = Y + '-'+ M + '-' + D1.padStart(2, '0')
    		
    		deliveryTimeList.push({ timezh: nextDay, timeformatter: todayYMD, timelist: nowDayList });
    		this.content = deliveryTimeList
    		
    		let nextDayStr = this.getTimeList('three');
    		let nextDayList = this.getTimeObj(nextDayStr)
    		
    		let D2 = new Date(new Date().setDate(new Date().getDate() + 2)).getDate().toString()
    		let nextYMD = Y + '-'+ M + '-' + D2.padStart(2, '0')
    		deliveryTimeList.push({ timezh: threeDay, timeformatter: nextYMD, timelist: nowDayList });
    		this.content = []
    		this.content = deliveryTimeList
    	} else {
    		let todayStr = this.getTimeList('one');
    		let nowDayList = this.getTimeObj(todayStr)
    		
    		let todayYMD = Y + '-'+ M + '-' + D.toString().padStart(2, '0')
    		deliveryTimeList.push({ timezh: today, timeformatter: todayYMD, timelist: nowDayList });
    		this.content = deliveryTimeList
    		
    		let nextDayStr = this.getTimeList('two');
    		let nextDayList = this.getTimeObj(nextDayStr)
    		let D2 = new Date(new Date().setDate(new Date().getDate() + 1)).getDate().toString()
    		let nextYMD = Y + '-' + M + '-' + D2.padStart(2, '0')
    		deliveryTimeList.push({ timezh: nextDay, timeformatter: nextYMD, timelist: nextDayList });
    		this.content = []
    		this.content = deliveryTimeList
    		
    	}
    	
    	this.chooseDate = this.content[0].timeformatter
    	this.chooseDay = this.content[0].timezh
        this.chooseTime = this.content[0].timelist[0].timestr
    },
    // 获取时间段
    getTimeList(hour, minut) {
    	let timeListTodayAll = [];
    	let timeList = []
		
    	let now = new Date()
    	let tommorrow = new Date().setDate(new Date().getDate() + 1)
    	let three = new Date().setDate(new Date().getDate() + 2)
    	let todayStart = new Date().getFullYear() + '-' + (new Date().getMonth() + 1).toString().padStart(2, '0') + '-' + new Date().getDate() + ' 09:00:00'
    	
    	let allTimes = (21 - 9) * 60 / 40
    	for(let i = 0; i < allTimes; i++) {
    		let setTodayTime = new Date(todayStart).setMinutes(40 * i)
    		timeListTodayAll.push(formatTime(setTodayTime))
    		timeList.push(formatTime(setTodayTime).substring(11, 16))
    	}
		if(type == 'one') {
			let nowTimeStamp = new Date().setMinutes(new Date().getMinutes() + 20)
			for(let j = 0; j < timeListTodayAll.length; j++) {
				let itemStamp = new Date(timeListTodayAll[j]).getTime()
				if(itemStamp >= nowTimeStamp) {
					timeList = timeList.slice(j)
					break
				}
			}
		}
		return timeList
    },
    // 根据时间段转为数组对象
    getTimeObj(todayStr){
    	// 将数组中的时间段字符串分割
    	let todayArr = []
    	todayStr.forEach(item => {
    		todayArr.push(...item.split('-'))
    	})
    	// 将分割后的数组去重
    	let todayDup = []
    	todayArr.forEach(item => {
    		if(todayDup.indexOf(item) == -1){
    			todayDup.push(item)
    		}
    	})
    	// 将去重后的数组转为数组对象
    	let todayList = []
    	todayDup.forEach(item => {
    		todayList.push({
    			timestr: item
    		})
    	})
    	return todayList;
    },
    
    // 控制弹窗显示
    showModel(){
    	this.model = true;
    },
    // 选择日期的回调
    dataCallback(item,index){
    	this.chooseDay = item.timezh
    	this.chooseDate = item.timeformatter
    },
    // 选择时间的回调
    timeCallback(item,index){
    	if(this.now == this.chooseDate){
    		this.chooseDay = this.content[0].timezh
    		this.chooseDate = this.now
    	}else{
    		this.chooseDay = this.content[1].timezh
    		this.chooseDate = this.content[1].timeformatter
    	}
    	this.chooseTime = item.timestr
    	
    	if(this.chooseDay != this.content[0].timezh || this.chooseTime != this.content[0].timelist[0].timestr) {
    		this.bhTxt = '指定时间'
    	} else {
    		this.bhTxt = '尽快取货'
    	}
    	this.model = false;
    },
  },
  onshow(){
	  let now = new Date();
	  let year = now.getFullYear()
	  let month = now.getMonth() + 1
	  month = month < 10 ? "0" + month : month;
	  let date = now.getDate() 
	  date = date < 10 ? '0' + date : date
	  this.chooseDate = `${year}-${month}-${date}`
	  this.now = `${year}-${month}-${date}`
	  this.getDliveryTime()
  }
}
</script>

css

<style lang="less" scoped>
.pinck-box {
  background: #ffffff;
  padding: 0 32rpx 17rpx 32rpx;
  .picker-up-title {
    font-size: 32rpx;
    font-weight: 500;
    color: #000000;
    padding: 20rpx 0;
  }
  .pick-item {
    height: 88rpx;
    background: #f4f4f4;
    border-radius: 24rpx 24rpx 24rpx 24rpx;
    padding: 0 32rpx;
    display: flex;
    align-items: center;
    justify-content: space-between;
    .block-up-title {
      font-size: 28rpx;
      font-weight: 400;
      color: #ff502f;
    }
    .block-up-time {
      font-size: 24rpx;
      font-weight: 400;
      color: #999999;
      display: flex;
      align-items: center;
      /deep/.uni-icons {
        font-size: 24rpx !important;
        color: #999999 !important;
      }
    }
  }
}
</style>