开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第4天,查看详情
需求: 只能选择当前的时间,不能选择未来的时间
u-picker组件原本的样子
开发背景: 1.在项目准备上线的时候,突然接到这个需求,当时想更换组件,在插件市场找了许久,其他的插件都不符合此需求 2. 自己编写的组件过于生硬,体验感不好
综合以上的情况,最后决定更改源码
思考: 假如当天时间是2022/11/20 15:47:00
- 如果滑动到年份是2022时,就不能选择选择12月份,若滑动到2021时则可以选择12月
- 如果滑动月份,年份是2022且是11月份,就不能选择20号往后的日期
- 如果滑动日期,年份是2022且是11月份20号时,就不能选择15时往后的时间
- 就是以此类推
所以应当从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));
},