Vue自定义组件选择区间段日期-基于mintui封装的日历组件

实现入下图所示需求:
在这里插入图片描述
在这里插入图片描述

组件的具体代码:

<template>
	<div class="calendar">
		<div class="calendar-box">
			<div class="title-area">
				<div class="title-div">日期选择</div>
				<i @click="cancelDate" class="iconfont icon-guanbi title-close"></i>
			</div>
			<div class="calendar-body">
				<div class="calendar-body-text">
					<div style="cursor: pointer" @click="month--"></div>
					<div class="text-title">{{timeValue}}</div>
					<div style="cursor: pointer" @click="month++"></div>
				</div>
				<table cellspacing="0" cellpadding="0">
					<thead>
						<tr>
							<th v-for="(h, i) in teheadList" :key="i">{{h}}</th>
						</tr>
					</thead>
					<tbody>
						<tr v-for="(b, i) in tbodyList" :key="i">
							<td @click="getCurrentDay(o)" v-for="(o, index) in b" :key="index"
								:class="[checkStart == (`${o.year}/${o.month}/${o.name}`)||checkEnd == (`${o.year}/${o.month}/${o.name}`) ? 'activeDay' : '',
								new Date(checkStart) < (new Date(`${o.year}/${o.month}/${o.name}`))&&new Date(checkEnd) > (new Date(`${o.year}/${o.month}/${o.name}`)) ? 'durationTime' : '',
								{'firstActive':checkStart == (`${o.year}/${o.month}/${o.name}`)&&checkEnd!=''},{'lastActive':checkEnd == (`${o.year}/${o.month}/${o.name}`)}]">
								<span :class="o.class" v-if="o.name == 'default'">{{o.name}}</span>
								<span :class="o.class + (day == o.name ? ' currentMonth' : '')" v-else>{{o.name}}</span>
								<div v-show="checkStart == (`${o.year}/${o.month}/${o.name}`)" class="tip start">开始</div>
								<div v-show="checkEnd == (`${o.year}/${o.month}/${o.name}`)" class="tip end">结束</div>
							</td>
						</tr>
					</tbody>
				</table>
			</div>
			<footer class="calendar-foot">
				<div class="surebtn" @click="sureDate">确定</div>
			</footer>
		</div>
	</div>
</template>

<script>
export default {
	name: 'calendar',
	data: () => {
		return {
			timeValue: '',
			teheadList: ['日', '一', '二', '三', '四', '五', '六'],
			year: '',
			month: 0,
			day: '',
			tbodyList: [],
			currentDay: '',
			checkStart: '', //开始日期
			checkEnd: '' //结束日期
		};
	},
	props: [],
	mounted() {
		this.getInitTime();
	},
	watch: {
		month() {
			if (this.month < 1) {
				this.month = 12;
				this.year--;
			} else if (this.month > 12) {
				this.month = 1;
				this.year++;
			}
			this.tbodyList = [];
			this.timeValue = this.year + '年' + this.month + '月';
			this.handleAetCalendar();
		}
	},
	methods: {
		//确定时间
		sureDate() {
			if (this.checkStart == '' || this.checkEnd == '') {
				this.Tool.tip('请选择开始时间和结束时间!');
				return;
			}
			let para = {
				type: 'sure',
				start: this.checkStart,
				end: this.checkEnd
			};
			this.$emit('sureDate', para);
		},
		//关闭弹窗
		cancelDate() {
			let para = {
				type: 'cancel',
				start: this.checkStart,
				end: this.checkEnd
			};
			this.$emit('sureDate', para);
		},
		//处理当前点击时间
		getCurrentDay(item) {
			let newVal = `${item.year}/${item.month}/${item.name}`;
			if (!this.checkStart || this.checkStart == '') {
				//开始时间赋值
				this.checkStart = newVal;
			} else {
				//已选定开始日期
				if (!this.checkEnd || this.checkEnd == '') {
					//未选择结束
					let start = new Date(`${this.checkStart}`);
					let current = new Date(`${newVal}`);
					if (start >= current) {
						//开始时间晚于结束时间
						this.checkStart = newVal;
					} else {
						this.checkEnd = newVal;
					}
				} else {
					//已选择结束时间
					this.checkStart = newVal;
					this.checkEnd = '';
				}
			}
		},
		//初始化时间
		getInitTime() {
			let date = new Date();
			this.year = date.getFullYear(); // 获取当年
			this.month = date.getMonth() + 1; // 获取本月
			this.day = date.getDate(); // 获取当天
			this.timeValue = date.getFullYear() + '年' + (date.getMonth() + 1) + '月';
			this.handleAetCalendar();
		},
		// 生成档期数据
		handleAetCalendar() {
			this.tbodyList = [];
			let days = new Date(this.year, this.month, 0).getDate(); // 当月总天数
			let week = new Date(this.year, this.month - 1, 1).getDay(); // 当月有几周
			let last_month = new Date(this.year, this.month + 1, 0).getDate(); // 当月的上一个月的最后一天
			this.tbodyList[0] = [];
			for (let i = 0; i < Math.ceil((days + week) / 7) * 7; i++) {
				let nub = Math.floor(i / 7);
				if (i < week) {
					this.tbodyList[nub].push({
						class: 'default',
						name: last_month + i - week + 1,
						month: this.month == 0 ? 12 : this.month - 1,
						year: this.month == 1 ? this.year - 1 : this.year
					});
				} else {
					if (!this.tbodyList[nub]) {
						this.tbodyList[nub] = [];
					}
					let day = i - week + 1;
					let className = 'actives';
					let month = this.month;
					let year = this.year;
					if (day > days) {
						day -= days;
						className = 'default';
						month = this.month + 1 > 12 ? 1 : this.month + 1;
						year = this.month + 1 > 12 ? this.year + 1 : this.year;
					}
					this.tbodyList[nub].push({
						class: className,
						name: day,
						month: month,
						year: year
					});
				}
			}
			let arr = this.tbodyList[Math.floor((week + days) / 7)];
			if (arr && arr.length !== 7) {
				this.tbodyList[Math.floor((week + days) / 7)] = arr.concat(
					new Array(7 - arr.length).fill('')
				);
			}
		}
	}
};
</script>

<style lang="scss" scoped>
.calendar {
	width: 100%;
	background: #dcdcdc;
	border-radius: 18px 18px 0px 0px;
	.calendar-box {
		width: 100%;
		background: #fff;
		height: 100%;
		position: relative;
		border-radius: 18px 18px 0px 0px;
		.title-area {
			position: relative;
			.title-div {
				width: 100%;
				text-align: center;
				font-size: 0.75rem;
				padding: 0.6rem;
			}
			.title-close {
				position: absolute;
				right: 0.75rem;
				top: 0.75rem;
				font-size: 0.65rem;
			}
		}
		.calendar-body {
			width: 100%;
			margin: 0 auto;
			padding: 0 0.7rem 0.7rem;
			font-size: 0.6rem;
			.calendar-body-text {
				width: 100%;
				height: 30px;
				display: flex;
				flex-direction: row;
				align-items: center;
				justify-content: center;
				.text-title {
					margin: 0 20px;
					font-size: 0.75rem;
				}
			}
		}
		table {
			font-size: 0;
		}
		table tr th {
			color: #666666;
		}
		table tr th,
		table tr td {
			width: 3.5rem;
			height: 50px;
			text-align: center;
			font-size: 0.6rem;
		}
		table td {
			position: relative;
			&.activeDay {
				background: #3a72dc;
				span {
					color: #fff;
				}
			}
			&.durationTime {
				background: #ecf2fb;
				span {
					color: #3a72dc;
				}
			}
			.tip {
				color: #fff;
			}
			.currentMonth {
				color: #00bfff;
			}
			&.firstActive {
				border-radius: 5px 0px 0px 5px;
			}
			&.lastActive {
				border-radius: 0px 5px 5px 0px;
			}
		}
		table td span {
			color: #343434;
			cursor: pointer;
		}
		table td span.default {
			color: #9a9a9a;
		}
		table td .tip {
			position: absolute;
			left: 0.7rem;
		}
		.calendar-foot {
			text-align: center;
			padding-bottom: 0.7rem;
			.surebtn {
				width: 7rem;
				display: inline-block;
				padding: 0.3rem;
				background: #3a72dc;
				color: #fff;
				font-size: 0.65rem;
				border-radius: 15px;
			}
		}
	}
}
</style>

调用该组件的页面:

<mt-popup class="datePopup" v-model="datePopupVisible" position="bottom">
	<CalendarCustom @sureDate="CheckedDate"></CalendarCustom>
</mt-popup>

点击确定后的传值:

CheckedDate(dateInfo) {
	this.datePopupVisible = false;
	if (dateInfo.type === 'cancel') {
		return;
	}
	this.assetDate = dateInfo.start + '到' + dateInfo.end;
},
.datePopup {
	width: 100%;
	border-radius: 18px 18px 0px 0px;
}

注:部分动画及提示框基于mintui,可修改、替换

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值