最近在做一些小程序项目,应项目需求开始学习wxml、wxss和js语法,其中有个地方需要用到选择器。在iOS中使用UIPickerView控件可以完成。同样在官方文档中也可以找到picker组件,微信小程序组件-picker
这种内置定义好的选择器都是从底部弹起。目前支持五种选择器,通过设置mode来区分。分别是普通选择器,多列选择器,时间选择器,日期选择器,省市区选择器,默认是普通选择器。
先贴上需求效果:这里我使用多列选择器,普通选择器、日期选择器和时间选择器没法实现。
首先定义在wxml中定义picker组件:
<picker class='time-picker' mode="multiSelector" bindchange="bindStartMultiPickerChange" bindtap='pickerTap' bindcolumnchange="bindMultiPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">{{startDate}}</picker>
这里定义的range为一个二维数组,现在数据是写定的:
// .js
multiArray: [['今天', '明天', '3-2', '3-3', '3-4', '3-5'], [0, 1, 2, 3, 4, 5, 6], [0, 10, 20]],
很明显这里的数据并不符合要求,按照需求,这里应该是展示当前的日期格式为:月-日 时 分
其中月-日列为:今天,明天,然后往后延28天。
时这里为0~23点 24个选项
分钟这里按照0~10,10~20,20~30,30~40,40~50来分段显示!
修改js代码:
pickerTap:function() {
var date = new Date();
var monthDay = ['今天','明天'];
var hours = [];
var minute = [];
// 月-日
for (var i = 2; i <= 28; i++) {
var date1 = new Date(date);
date1.setDate(date.getDate() + i);
var md = (date1.getMonth() + 1) + "-" + date1.getDate();
monthDay.push(md);
}
// 时
for (var i = 0; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
var data = {
multiArray: this.data.multiArray,
multiIndex: this.data.multiIndex
};
data.multiArray[0] = monthDay;
data.multiArray[1] = hours;
data.multiArray[2] = minute;
this.setData(data);
},
在pickerTap函数中定义三个数组分别储存月-日、时、分。
但是发现选择今天的时候,时、分是可以在0~23、0~50之间选择的。如果现在是上午9点,我们在选择今天的时间候就只能选择9点以后的了。所以这里需要改进一下。如果选择今天,那么时、分中只能是当前时间往后的选项。
这里还有一点需要注意,如果今天时间是9:55。那么选项中首条应该怎么展示。首先时这里应该是10点往后延,而分就是0~50了。所以在获取到当前分还需要做判断才能给hours和minute赋值,具体看一下代码:
var currentHours = date.getHours();
var currentMinute = date.getMinutes();
// 月-日
for (var i = 2; i <= 28; i++) {
var date1 = new Date(date);
date1.setDate(date.getDate() + i);
var md = (date1.getMonth() + 1) + "-" + date1.getDate();
monthDay.push(md);
}
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours+1; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = minuteIndex; i < 60; i += 10) {
minute.push(i);
}
}
首先获取当前时分,并给分值分段。如果minuteIndex = 60,也就是当前分为50~60之间。这种情况下就是当前时+1,分为0~50。否则就是当前时~23点,当前分在那个分段~50这样显示。具体需求:
当选择今天。时为当前时,那么分就展示当前分段~50选项。
当选择今天。时不为当前时,那么分就展示 0~50选项。
当第一列不为今天,那么时就为 0~23选项,分就为0~50的选项。
按照需求来代码实现:
bindMultiPickerColumnChange:function(e) {
date = new Date();
var that = this;
var monthDay = ['今天', '明天'];
var hours = [];
var minute = [];
currentHours = date.getHours();
currentMinute = date.getMinutes();
var data = {
multiArray: this.data.multiArray,
multiIndex: this.data.multiIndex
};
// 把选择的对应值赋值给 multiIndex
data.multiIndex[e.detail.column] = e.detail.value;
// 然后再判断当前改变的是哪一列,如果是第1列改变
if (e.detail.column === 0) {
// 如果第一列滚动到第一行
if (e.detail.value === 0) {
that.loadData(hours, minute);
} else {
that.loadHoursMinute(hours, minute);
}
data.multiIndex[1] = 0;
data.multiIndex[2] = 0;
// 如果是第2列改变
} else if (e.detail.column === 1) {
// 如果第一列为今天
if (data.multiIndex[0] === 0) {
if (e.detail.value === 0) {
that.loadData(hours, minute);
} else {
that.loadMinute(hours, minute);
}
// 第一列不为今天
} else {
that.loadHoursMinute(hours, minute);
}
data.multiIndex[2] = 0;
// 如果是第3列改变
} else {
// 如果第一列为'今天'
if (data.multiIndex[0] === 0) {
// 如果第一列为 '今天'并且第二列为当前时间
if(data.multiIndex[1] === 0) {
that.loadData(hours, minute);
} else {
that.loadMinute(hours, minute);
}
} else {
that.loadHoursMinute(hours, minute);
}
}
data.multiArray[1] = hours;
data.multiArray[2] = minute;
this.setData(data);
},
loadData: function (hours, minute) {
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours + 1; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = minuteIndex; i < 60; i += 10) {
minute.push(i);
}
}
},
loadHoursMinute: function (hours, minute){
// 时
for (var i = 0; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
},
loadMinute: function (hours, minute) {
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours + 1; i < 24; i++) {
hours.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
},
简要说明一下。picker每列数据变动事都会调bindMultiPickerColumnChange函数。首先每次拿到最新时间,并更新全局当前时、分:
date = new Date();
currentHours = date.getHours();
currentMinute = date.getMinutes();
拿到page-data里面的multiArray:元数据数组和muliIndex:picker改变数据数组:
multiArray: this.data.multiArray,
multiIndex: this.data.multiIndex
picker改动的列索引和对应的值在e.detail中,所以每次改变,就把值赋值给multiIndex:
data.multiIndex[e.detail.column] = e.detail.value;
现在开始判断了,如果第一列或第二列或第三列发生改变:
if (e.detail.column === 0) {
// 如果第一列滚动到第一行
if (e.detail.value === 0) {
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours + 1; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = minuteIndex; i < 60; i += 10) {
minute.push(i);
}
}
} else {
// 时
for (var i = 0; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
}
data.multiIndex[1] = 0;
data.multiIndex[2] = 0;
}
如果是第一列发生改变,并且是滚动到0,也就是滚动到 '今天' 的时候,第二列和第三列对应的应该变为当前时和分来显示。这里的minuteIndex定义为局部变量,是把当前分划分到哪个时间段的。如果在0~10之内,那么分钟显示为10、20、30、40、50。如果在40~50之间的话,分钟应该显示为50。如果分钟在50~60之间的话,这个时候小时应该+1,并且分钟为0、10、20、30、40、50。
如果当前为18:54,那么显示应该如下:上面是对第一列为 '今天的操作',如果第一列不为今天,那么第二列和第三列就应该显示全部数据。也就是下面这段代码:
// 时
for (var i = 0; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
给hours和minute赋值之后,最后再赋值给multiArray就可以显示出来了。
最后一一步就是在第一列改变的时候,第二列和第三列相应都滚动到0号位。
data.multiIndex[1] = 0;
data.multiIndex[2] = 0;
接下来是第二列改变的判断:
else if (e.detail.column === 1) {
// 如果第一列为今天
if (data.multiIndex[0] === 0) {
if (e.detail.value === 0) {
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours + 1; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = minuteIndex; i < 60; i += 10) {
minute.push(i);
}
}
} else {
var minuteIndex;
if (currentMinute > 0 && currentMinute <= 10) {
minuteIndex = 10;
} else if (currentMinute > 10 && currentMinute <= 20) {
minuteIndex = 20;
} else if (currentMinute > 20 && currentMinute <= 30) {
minuteIndex = 30;
} else if (currentMinute > 30 && currentMinute <= 40) {
minuteIndex = 40;
} else if (currentMinute > 40 && currentMinute <= 50) {
minuteIndex = 50;
} else {
minuteIndex = 60;
}
if (minuteIndex == 60) {
// 时
for (var i = currentHours + 1; i < 24; i++) {
hours.push(i);
}
} else {
// 时
for (var i = currentHours; i < 24; i++) {
hours.push(i);
}
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
}
// 第一列不为今天
} else {
// 时
for (var i = 0; i < 24; i++) {
hours.push(i);
}
// 分
for (var i = 0; i < 60; i += 10) {
minute.push(i);
}
}
data.multiIndex[2] = 0;
}
如果第二列发生改变,要根据第一列的位置来改变hours和minute的值。所以如果第一列为0,也就是'今天',并且第二列也为0,那么第二列和第三列应该根据当前时间进行显示。如果第二列不为0。那么第二列根据当前时来显示,但是第三列应该是0~50全部显示。如果第一列不为'今天'。这个时候第二列和第三列都应该全部显示,也就是0~23、0~50。最后需要滚动第三列到0号位:
data.multiIndex[2] = 0;
同样如果第三列发生改变,也要根据第一列和第二列的位置来显示。如果第一列为0,第二列为0,那么这里的hours和minute应该根据当前时间来显示。如果第二列不为0,那么minute应该是0~50显示全部选项。最后如果第一列也不为0,那么hours和minute都应该全部显示。
最后把hours和minute赋值到data:
data.multiArray[1] = hours;
data.multiArray[2] = minute;
this.setData(data);
写到这里,最后的效果就如开头展示的那样。
第一次写小程序文章,如果有错误或者讲得不到位的地位欢迎留言讨论,谢谢。
最后补充一下,如果currentHours或currentHours+1 大于等于24的话要进行判断处理。
本文源码:GitHub WXProgram