微信小程序日期+时间选择器

最近在做一些小程序项目,应项目需求开始学习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函数中定义三个数组分别储存月-日、时、分。

然后在当前日期上往后延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的话要进行判断处理。

本文源码:GitHub WXProgram

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 161,873评论 4 370
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,483评论 1 306
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 111,525评论 0 254
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,595评论 0 218
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 53,018评论 3 295
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,958评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,118评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,873评论 0 208
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,643评论 1 250
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,813评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,293评论 1 265
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,615评论 3 262
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,306评论 3 242
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,170评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,968评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 36,107评论 2 285
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,894评论 2 278

推荐阅读更多精彩内容

  • 在一些电商类的微信小程序中,地址选择这个功能一般是必备的,一般的收货信息都需要有一个能选择省市县的控件,当然也有些...
    第九程序官方阅读 3,862评论 0 6
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 10,533评论 6 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,110评论 18 139
  • 马的意志 一匹健壮的骏马,向着远方艰难跋涉,它怀着远大的梦想,用自己的足走遍千山万水,游尽大山内外,不负从小立下的...
    南溪向南北歌流海阅读 373评论 0 0
  • 扩展NSMutableDictionary的一个类别,上面注释说的很清楚,除非value为nil的时候,调用方法 ...
    小笨憨阅读 247评论 0 0