0

    微信小程序----日期时间选择器(自定义精确到分秒或时段)(MUI日期时间)

    2023.04.20 | admin | 144次围观

    最近在做一些小程序项目,应项目需求开始学习wxml、wxss和js语法,其中有个地方需要用到选择器。在iOS中使用UIPickerView控件可以完成。同样在官方文档中也可以找到picker组件,微信小程序组件-picker

    这种内置定义好的选择器都是从底部弹起。目前支持五种选择器,通过设置mode来区分。分别是普通选择器,多列选择器,时间选择器,日期选择器,省市区选择器,默认是普通选择器。

    先贴上需求效果:

    这里我使用多列选择器,普通选择器、日期选择器和时间选择器没法实现。

    首先定义在wxml中定义picker组件:

    {{startDate}}

    复制

    这里定义的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函数中定义三个数组分别储存月-日、时、分。

    然后在当前日期上往后延2-28天,并分别push到monthDay数组中。时和分比较好添加。添加完毕最后赋值给multiArray。在编译的话月-日、时、分总算完整了。

    但是发现选择今天的时候,时、分是可以在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这样显示。

    虽然这样改进之后第一次点开picker展示没问题。但是在开始选择时就不行了。当时选择17,这里的分展示肯定有问题。所以这里的数据我们还需要根据每列的选择来变动。

    具体需求:当选择今天。时为当前时,那么分就展示当前分段~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的话要进行判断处理。

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论