uni-app u-picker时间弹框

427 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,查看详情

需求: 只能选择当前的时间,不能选择未来的时间

image.png

u-picker组件原本的样子

image.png

开发背景: 1.在项目准备上线的时候,突然接到这个需求,当时想更换组件,在插件市场找了许久,其他的插件都不符合此需求 2. 自己编写的组件过于生硬,体验感不好

综合以上的情况,最后决定更改源码

思考: 假如当天时间是2022/11/20 15:47:00

  1. 如果滑动到年份是2022时,就不能选择选择12月份,若滑动到2021时则可以选择12月
  2. 如果滑动月份,年份是2022且是11月份,就不能选择20号往后的日期
  3. 如果滑动日期,年份是2022且是11月份20号时,就不能选择15时往后的时间
  4. 就是以此类推

所以应当从watch()里的监听年份/月份/日期发生变化的函数开始着手

1.首先找到源码的位置

在 node_modules > uview-ui > u-picker > u-picker.vue

2.watch的代码

watch: {
		propsChange() {
			this.reset = true;
			setTimeout(() => this.init(), 10);
		},
		// 如果地区发生变化,为了让picker联动起来,必须重置this.citys和this.areas
		regionChange(val) {
			this.citys = citys[this.province];
			this.areas = areas[this.province][this.city];
		},
		// watch监听月份的变化,实时变更日的天数,因为不同月份,天数不一样
		// 一个月可能有30,31天,甚至闰年2月的29天,平年2月28天
		yearChange(val) {
			if (this.params.year) this.setMonths();
		},
		yearAndMonth(val) {
			if (this.params.year) this.setDays();
		},
		hoursChange(val) {
			if (this.params.year) this.setHours();
		},
		minutesChange(val) {
		   if (this.params.year) this.setMinutes();
		},
		// 微信和QQ小程序由于一些奇怪的原因(故同时对所有平台均初始化一遍),需要重新初始化才能显示正确的值
		value(n) {
			if (n) {
				this.reset = true;
				setTimeout(() => this.init(), 10);
			}
		}
	},

3.computed的代码

computed: {
		propsChange() {
			// 引用这几个变量,是为了监听其变化
			return `${this.mode}-${this.defaultTime}-${this.startYear}-${this.endYear}-${this.defaultRegion}-${this.areaCode}`;
		},
		regionChange() {
			// 引用这几个变量,是为了监听其变化
			return `${this.province}-${this.city}`;
		},
		yearChange() {
			return `${this.year}`;
		},
		yearAndMonth() {
			return `${this.year}-${this.month}`;
		},
		hoursChange() {
			return `${this.year}-${this.month}-${this.day}`;
		},
		minutesChange(val) {
		   return `${this.year}-${this.month}-${this.day}-${this.hour}`;
		},
		uZIndex() {
			// 如果用户有传递z-index值,优先使用
			return this.zIndex ? this.zIndex : this.$u.zIndex.popup;
		}
	},

4.methods的代码

                setYears() {
			// 获取年份集合
			console.log('this.years',this.years,this.year)
			this.years = this.generateArray(this.startYear, this.endYear);
			// 设置this.valueArr某一项的值,是为了让picker预选中某一个值
			this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.years, this.year));
		},
                setMonths() {
			if (new Date().getFullYear() != this.year) {
				this.months = this.generateArray(1, 12);
			} else {
				this.months = this.generateArray(1, new Date().getMonth() + 1);
			}
			this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.months, this.month));
		},
		setDays() {
			console.log('month',this.month)
			let totalDays = new Date(this.year, this.month, 0).getDate();
			// this.days = this.generateArray(1, totalDays);
			// this.days = this.generateArray(new Date().getDate(), totalDays);
			if (this.month != (new Date).getMonth() + 1 || new Date().getFullYear() != this.year) {
				this.days = this.generateArray(1, totalDays);
			}else {
				this.days = this.generateArray(1, new Date().getDate());
			}
			
			let index = 0;
			// 这里不能使用类似setMonths()中的this.valueArr.splice(this.valueArr.length - 1, xxx)做法
			// 因为this.month和this.year变化时,会触发watch中的this.setDays(),导致this.valueArr.length计算有误
			if (this.params.year && this.params.month) index = 2;
			else if (this.params.month) index = 1;
			else if (this.params.year) index = 1;
			else index = 0;
			// 当月份变化时,会导致日期的天数也会变化,如果原来选的天数大于变化后的天数,则重置为变化后的最大值
			// 比如原来选中3月31日,调整为2月后,日期变为最大29,这时如果day值继续为31显然不合理,于是将其置为29(picker-column从1开始)
			if(this.day > this.days.length) this.day = this.days.length;
			this.valueArr.splice(index, 1, this.getIndex(this.days, this.day));
		},
		setHours() {
			console.log('this.day',this.day)
			if (this.year != new Date().getFullYear() || this.month != (new Date).getMonth() + 1 || this.day != (new Date).getDate()) {
				this.hours = this.generateArray(0, 23);
			}else {
				this.hours = this.generateArray(0, new Date().getHours());
			}
			
			// this.hours = this.generateArray(0, 23);
			this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.hours, this.hour));
		},
		setMinutes() {
			
			if (this.year != new Date().getFullYear() || this.month != (new Date).getMonth() + 1 || this.day != (new Date).getDate() || this.hour != (new Date).getHours() ) {
				this.minutes = this.generateArray(0, 59);
			}else {
				this.minutes = this.generateArray(0, new Date().getMinutes());
			}
			// this.minutes = this.generateArray(0, 59);
			this.valueArr.splice(this.valueArr.length - 1, 1, this.getIndex(this.minutes, this.minute));
		},