vue组件 -- 实现一种小时级时间段选择


效果

操作大概是选择一个开始时间和一个结束时间(从左往右选是选择,从右往左是取消),排除已选后计算他们总的时间段。

 

code

<template>
	<div>
		<div class="hours-container">
			<div v-for="(item, index) in hours" :key="index" class="hours-item">
				<div class="hours-item-header">{{ compItem(item) }}</div>
				<div class="hours-item-value">
					<div
						:class="compClass(2 * item)"
						@click="handleClick(2 * item)"
						@mouseover="handleHover(2 * item)"
					></div>
					<div
						:class="compClass(2 * item + 1)"
						@click="handleClick(2 * item + 1)"
						@mouseover="handleHover(2 * item + 1)"
					></div>
				</div>
			</div>
		</div>
		<div class="tips">{{ tips }}</div>
	</div>
</template>

<script>
/*
* @Description 为了实现24小时区间选择,若有星期的需求直接看 TimeRangeList组件
* @Author dengkangning
* @Date 2020年11月18日 16:33:19
*/
export default {
	model: {
		prop: "sendTimeList",
	},
	props: {
		sendTimeList: {
			required: true,
			default: []
		},
		readonly: {
			type: Boolean,
			default: false
		}
	},
	watch: {
		timeRangeList: function (value) {
			this.$emit('change', value);
			this.$parent.$emit("el.form.change");// 触发父组件的校验规则
		},
		sendTimeList:{
            handler () {
                this.transformedIndex();
            },
            deep:true
        }
	},
	computed: {
	},
	data() {
		return {
			hours: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22],// 选项
			selectStart: false,// 开始
			startIndex: '',// 开始下标
			timeRangeList: [],// 选择的时间段
			timeRangeListIndex: [],// 选中的下标
			tempRangeIndex: [],// 预选下标
			tips: '向右选中,向左取消选择'
		}
	},
	methods: {
		// 时间区间转换成下标区间
		transformedIndex() {
			this.timeRangeListIndex = [];
			this.timeRangeList = this.sendTimeList;
			this.timeRangeList.forEach(element => {
				const [startTime, endTime] = element.match(/\d+\:\d+/g);
				if (startTime && endTime) {
					let [startHour, startMin] = startTime.split(':');
					let [endHour, endMin] = endTime.split(':');
					if (startHour && startMin && endHour && endMin) {
						let startNum, endNum;
						if (startMin === '00') {
							startNum = 2 * parseInt(startHour);
						} else {
							startNum = 2 * parseInt(startHour) + 1;
						}
						if (endMin === '00') {
							endNum = 2 * parseInt(endHour) - 1;
						} else {
							endNum = 2 * parseInt(endHour);
						}
						while (endNum >= startNum) {
							this.timeRangeListIndex.push(startNum);
							startNum++;
						}

					} else {
						this.$message.error("时间段格式不正确");
					}

				} else {
					this.$message.error("没有拿到开始时间或结束时间或者时间段格式不对");
				}
			});
			this.tips = this.timeRangeList && this.timeRangeList.length > 0 ? this.timeRangeList : '向右选中,向左取消选择';
		},
		// 下标区间转换成时间区间
		transformedSection() {
			this.timeRangeList = [];
			let startTime = '', endTime = '', len = this.hours.length;
			for (let index = this.hours[0] * 2; index < 2 * (len + 1); index++) {
				if (this.timeRangeListIndex.indexOf(index) > -1) {
					if (startTime) {// 如果有开始时间,直接确定结束时间
						let endHour = Math.floor((index + 1) / 2);
						let endMin = (index + 1) % 2 === 0 ? "00" : "30";
						endTime = `${endHour < 10 ? '0' + endHour : endHour}:${endMin}`;
					} else {// 没有开始时间,确定当前点为开始时间
						let startHour = Math.floor(index / 2);
						let startMin = index % 2 === 0 ? "00" : "30";
						startTime = `${startHour < 10 ? '0' + startHour : startHour}:${startMin}`;
					}
					if (index === 2 * this.hours.length + 1) { // 如果是最后一格,直接结束
						endTime = `${Math.floor((index + 1) / 2)}:00`;
						this.timeRangeList.push(`${startTime ? startTime : "23:30"}-${endTime}`);
						startTime = '';
						endTime = '';
					}
				} else { // 若这个点不在选择区间,确定一个时间段
					if (startTime && endTime) {
						this.timeRangeList.push(`${startTime}-${endTime}`);
						startTime = '';
						endTime = '';
					} else if (startTime && !endTime) {// 这里可能只选半个小时
						let endHour = Math.floor(index / 2);
						let endMin = index % 2 === 0 ? "00" : "30";
						endTime = `${endHour < 10 ? '0' + endHour : endHour}:${endMin}`;
						this.timeRangeList.push(`${startTime}-${endTime}`);
						startTime = '';
						endTime = '';
					}
				}
			}
			this.tips = this.timeRangeList && this.timeRangeList.length > 0 ? this.timeRangeList : '向右选中,向左取消选择';
		},
		// 点击事件
		handleClick(index) {
			if (this.selectStart) {
				if (index === this.startIndex) {// 双击取反
					if (this.timeRangeListIndex.indexOf(index) > -1) {
						this.timeRangeListIndex.splice(this.timeRangeListIndex.indexOf(index), 1);
					} else {
						this.timeRangeListIndex.push(this.startIndex);
					}
				} else if (index > this.startIndex) {// 选取数据--向右添加,向左取消
					while (index >= this.startIndex) {
						this.timeRangeListIndex.push(this.startIndex);
						this.startIndex++;
					}
					this.timeRangeListIndex = Array.from(new Set(this.timeRangeListIndex));
				} else {// 删除数据
					while (this.startIndex >= index) {
						if (this.timeRangeListIndex.indexOf(index) > -1) {
							this.timeRangeListIndex.splice(this.timeRangeListIndex.indexOf(index), 1);
						}
						index++;
					}
				}
				this.startIndex = '';
				this.tempRangeIndex = [];
				this.transformedSection();
			} else {
				this.startIndex = index;
			}
			this.selectStart = !this.selectStart;
		},
		// 预选区间
		handleHover(index) {
			if (this.selectStart) {
				this.tempRangeIndex = [];
				if (index > this.startIndex) {// 选取数据--向右添加,向左取消
					while (index >= this.startIndex) {
						this.tempRangeIndex.push(index);
						index--;
					}
				} else {// 删除数据
					while (this.startIndex >= index) {
						this.tempRangeIndex.push(index);
						index++;
					}
				}
			}
		},
		// 是否选中,计算className
		compClass(index) {
			if (index === this.startIndex) {
				return 'hours-item-left preSelected';
			}
			if (index >= this.startIndex) {
				if (this.tempRangeIndex.indexOf(index) > -1) {
					return 'hours-item-left preSelected';
				}
			} else {
				if (this.tempRangeIndex.indexOf(index) > -1) {
					return 'hours-item-left unSelected';
				}
			}
			return this.timeRangeListIndex.indexOf(index) > -1 ? 'hours-item-left selected' : 'hours-item-left';
		},
		compItem(item) {// 不足10前面补0
			return item < 10 ? `0${item}` : item;
		},

	},
	mounted() {
		this.transformedIndex();
	}
}
</script>

<style lang="scss" scoped>
.hours-container {
	display: flex;
	cursor: pointer;
	.hours-item {
		width: 30px;
		height: 60px;
		border: 1px solid #c2d0f3;
		border-right: none;
		text-align: center;
		&:last-child {
			border-right: 1px solid #c2d0f3;
		}
		.hours-item-header {
			width: 100%;
			height: 30px;
			line-height: 30px;
			border-bottom: 1px solid #c2d0f3;
		}
		.hours-item-value {
			width: 100%;
			height: 30px;
			box-sizing: border-box;
			display: flex;
			.hours-item-left,
			.hours-item-right {
				width: 50%;
				height: 100%;
				border-right: 1px solid #c2d0f3;
				box-sizing: border-box;
				&:last-child {
					border-right: none;
				}
			}
		}
		.selected {
			background-color: #4e84fe;
			border-bottom: 1px solid #c2d0f3;
		}
		.preSelected {
			background-color: #8eaffc;
			border-bottom: 1px solid #c2d0f3;
		}
		.unSelected {
			background-color: #ffffff;
			border-bottom: 1px solid #c2d0f3;
		}
	}
}
.tips {
	width: 100%;
	line-height: 30px;
}
</style>

 

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值