评论

自定义可配置format的日期时间选择组件DateTimePicker

通用时间选择器DateTimePicker

背景

由于在项目中遇到需要同时选择日期和时间的需求,所以自己写了一个可以动态配置format格式的时间选择器

效果图

wxml

<view class="view-body">
  <text class='item-key'>{{title}}<text style="color:red" wx:if="{{isRequired}}">*</text></text>
  <view class="item-value">
    <picker mode="multiSelector" bindchange="bindPickerChange" bindcolumnchange="bindPickerColumnChange" value="{{multiIndex}}" range="{{multiArray}}">
      <input disabled="{{true}}" value='{{value}}' name='{{name}}' />
      <image class="img-arrow" src='/images/date_icon.png' />
    </picker>
  </view>
</view>

js

Component({
  behaviors: ['wx://form-field'],
  properties: {
    title: {
      type: String
    },
    name: {
      type: String
    },
    isRequired: {
      type: Boolean
    },
    format: {
      type: String
    }
  },
  data: {},
  lifetimes: {
    attached: function() {
      //当前时间 年月日 时分秒
      const date = new Date()
      const curYear = date.getFullYear()
      const curMonth = date.getMonth() + 1
      const curDay = date.getDate()
      const curHour = date.getHours()
      const curMinute = date.getMinutes()
      const curSecond = date.getSeconds()

      //记录默认年份 后面加载二月份天数
      this.setData({
        chooseYear: curYear
      })
      //初始化时间选择轴
      this.initColumn(curMonth)

      //不足两位的前面好补0 因为后面要获取在时间轴上的索引 时间轴初始化的时候都是两位
      let showMonth = curMonth < 10 ? ('0' + curMonth) : curMonth
      let showDay = curDay < 10 ? ('0' + curDay) : curDay
      let showHour = curHour < 10 ? ('0' + curHour) : curHour
      let showMinute = curMinute < 10 ? ('0' + curMinute) : curMinute
      let showSecond = curSecond < 10 ? ('0' + curSecond) : curSecond

      //当前时间在picker列上面的索引 为了当打开时间选择轴时选中当前的时间
      let indexYear = this.data.years.indexOf(curYear + '')
      let indexMonth = this.data.months.indexOf(showMonth + '')
      let indexDay = this.data.days.indexOf(showDay + '')
      let indexHour = this.data.hours.indexOf(showHour + '')
      let indexMinute = this.data.minutes.indexOf(showMinute + '')
      let indexSecond = this.data.seconds.indexOf(showSecond + '')

      let multiIndex = []
      let multiArray = []
      let value = ''

      let format = this.properties.format;
      if (format == 'yyyy-MM-dd') {
        multiIndex = [indexYear, indexMonth, indexDay]
        value = `${curYear}-${showMonth}-${showDay}`
        multiArray = [this.data.years, this.data.months, this.data.days]
      }
      if (format == 'HH:mm:ss') {
        multiIndex = [indexHour, indexMinute, indexSecond]
        value = `${showHour}:${showMinute}:${showSecond}`
        multiArray = [this.data.hours, this.data.minutes, this.data.seconds]
      }
      if (format == 'yyyy-MM-dd HH:mm') {
        multiIndex = [indexYear, indexMonth, indexDay, indexHour, indexMinute]
        value = `${curYear}-${showMonth}-${showDay} ${showHour}:${showMinute}`
        multiArray = [this.data.years, this.data.months, this.data.days, this.data.hours, this.data.minutes]
      }
      if (format == 'yyyy-MM-dd HH:mm:ss') {
        multiIndex = [indexYear, indexMonth, indexDay, indexHour, indexMinute, indexSecond]
        value = `${curYear}-${showMonth}-${showDay} ${showHour}:${showMinute}:${showSecond}`
        multiArray = [this.data.years, this.data.months, this.data.days, this.data.hours, this.data.minutes, this.data.seconds]

      }
      this.setData({
        value,
        multiIndex,
        multiArray,
        curMonth,
        chooseYear: curYear,

      })
    }
  },
  /**
   * 组件的方法列表
   */
  methods: {
    //获取时间日期
    bindPickerChange: function(e) {
      this.setData({
        multiIndex: e.detail.value
      })
      const index = this.data.multiIndex
      let format = this.properties.format
      var showTime = ''

      if (format == 'yyyy-MM-dd') {
        const year = this.data.multiArray[0][index[0]]
        const month = this.data.multiArray[1][index[1]]
        const day = this.data.multiArray[2][index[2]]
        showTime = `${year}-${month}-${day}`
      }
      if (format == 'HH:mm:ss') {
        const hour = this.data.multiArray[0][index[0]]
        const minute = this.data.multiArray[1][index[1]]
        const second = this.data.multiArray[2][index[2]]
        showTime = `${hour}:${minute}:${second}`
      }
      if (format == 'yyyy-MM-dd HH:mm') {
        const year = this.data.multiArray[0][index[0]]
        const month = this.data.multiArray[1][index[1]]
        const day = this.data.multiArray[2][index[2]]
        const hour = this.data.multiArray[3][index[3]]
        const minute = this.data.multiArray[4][index[4]]
        showTime = `${year}-${month}-${day} ${hour}:${minute}`
      }
      if (format == 'yyyy-MM-dd HH:mm:ss') {
        const year = this.data.multiArray[0][index[0]]
        const month = this.data.multiArray[1][index[1]]
        const day = this.data.multiArray[2][index[2]]
        const hour = this.data.multiArray[3][index[3]]
        const minute = this.data.multiArray[4][index[4]]
        const second = this.data.multiArray[5][index[5]]
        showTime = `${year}-${month}-${day} ${hour}:${minute}:${second}`
      }
      this.setData({
        value: showTime
      })
      this.triggerEvent('dateTimePicker', showTime)
    },
    //初始化时间选择轴
    initColumn(curMonth) {
      let years = []
      let months = []
      let days = []
      let hours = []
      let minutes = []
      let seconds = []
      for (let i = 1990; i <= 2099; i++) {
        years.push(i + '')
      }
      for (let i = 1; i <= 12; i++) {
        if (i < 10) {
          i = "0" + i;
        }
        months.push(i + '')
      }

      if (curMonth == 1 || curMonth == 3 || curMonth == 5 || curMonth == 7 || curMonth == 8 || curMonth == 10 || curMonth == 12) {
        for (let i = 1; i <= 31; i++) {
          if (i < 10) {
            i = "0" + i;
          }
          days.push(i + '')
        }
      }
      if (curMonth == 4 || curMonth == 6 || curMonth == 9 || curMonth == 11) {
        for (let i = 1; i <= 30; i++) {
          if (i < 10) {
            i = "0" + i;
          }
          days.push(i + '')
        }
      }
      if (curMonth == 2) {
        days=this.setFebDays()
      }
      for (let i = 0; i <= 23; i++) {
        if (i < 10) {
          i = "0" + i;
        }
        hours.push(i + '')
      }
      for (let i = 0; i <= 59; i++) {
        if (i < 10) {
          i = "0" + i;
        }
        minutes.push(i + '')
      }
      for (let i = 0; i <= 59; i++) {
        if (i < 10) {
          i = "0" + i;
        }
        seconds.push(i + '')
      }
      this.setData({
        years,
        months,
        days,
        hours,
        minutes,
        seconds
      })
    },

    /**
     * 列改变时触发
     */
    bindPickerColumnChange: function(e) {
      //获取年份 用于计算改年的2月份为平年还是闰年
      if (e.detail.column == 0 && this.properties.format != 'HH:mm:ss') {
        let chooseYear = this.data.multiArray[e.detail.column][e.detail.value];
        this.setData({
          chooseYear
        })
        if (this.data.curMonth == '02' || this.data.chooseMonth == '02') {
          this.setFebDays()
        }
      }
      //当前第二为月份时需要初始化当月的天数
      if (e.detail.column == 1 && this.properties.format != 'HH:mm:ss') {
        let num = parseInt(this.data.multiArray[e.detail.column][e.detail.value]);
        let temp = [];
        if (num == 1 || num == 3 || num == 5 || num == 7 || num == 8 || num == 10 || num == 12) { //31天的月份
          for (let i = 1; i <= 31; i++) {
            if (i < 10) {
              i = "0" + i;
            }
            temp.push("" + i);
          }
          this.setData({
            ['multiArray[2]']: temp
          });
        } else if (num == 4 || num == 6 || num == 9 || num == 11) { //30天的月份
          for (let i = 1; i <= 30; i++) {
            if (i < 10) {
              i = "0" + i;
            }
            temp.push("" + i);
          }
          this.setData({
            ['multiArray[2]']: temp
          });
        } else if (num == 2) { //2月份天数
          this.setFebDays()
        }
      }
      let data = {
        multiArray: this.data.multiArray,
        multiIndex: this.data.multiIndex
      };
      data.multiIndex[e.detail.column] = e.detail.value;
      this.setData(data);
    },
    //计算二月份天数
    setFebDays() {
      let year = parseInt(this.data.chooseYear);
      let temp = [];
      if (year % (year % 100 ? 4 : 400) ? false : true) {
        for (let i = 1; i <= 29; i++) {
          if (i < 10) {
            i = "0" + i;
          }
          temp.push("" + i);
        }
        this.setData({
          ['multiArray[2]']: temp,
          chooseMonth: '02'

        });
      } else {
        for (let i = 1; i <= 28; i++) {
          if (i < 10) {
            i = "0" + i;
          }
          temp.push("" + i);
        }
        this.setData({
          ['multiArray[2]']: temp,
          chooseMonth: '02'
        });
      }
      return temp;
    }
  },
})

wxss

.view-body {
  display: flex;
  align-items: center;
  padding: 4% 0%;
  border-bottom: 1px solid #eee;
}

.item-key {
  font-size: 30rpx;
  color: #666;
  width: 25%;
}

.item-value {
  flex-grow: 1;
  font-size: 31rpx;
  position: relative;
  margin-left: 3%;
}

.img-arrow {
  width: 45rpx;
  height: 45rpx;
  padding-right: 10rpx;
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  right: 5rpx;
}

使用

在你页面中的json中添加引用,路径根据你的实际工程目录来写。

{
  "usingComponents": {
    "DateTimePicker": "/components/datetimepicker/datetimepicker"
  }
}

wxml中添加

<DateTimePicker title='选择时间' isRequired='true' bind:dateTimePicker='onDateTimePicker' name='time' format='yyyy-MM-dd HH:mm:ss'/>

说明

  • title:表单组件的名称
  • isRequired:是否必填项
  • dateTimePicker:为选中确认回调
  • name:为表单点击 form 表单中 form-type 为 submit 的 button 组件时,会将表单组件中的 value 值进行提交,需要在表单组件中加上 name 来作为 key
  • format:时间格式化参数 支持:‘yyyy-MM-dd HH:mm:ss’,‘HH:mm:ss’,‘yyyy-MM-dd HH:mm’,‘yyyy-MM-dd’ 四种

开发者可以根据自己的需求调整组件样式


最后代码片段如下:
https://developers.weixin.qq.com/s/PzmDvcmi79fI

最后一次编辑于  2020-02-17  
点赞 7
收藏
评论

6 个评论

  • Q1an
    Q1an
    2020-12-01

    建议在picker列加上中文,这样更加直观

    2020-12-01
    赞同 3
    回复
  • TNT
    TNT
    2019-10-30

    老哥。用markdown写下文章。这个代码 不太容易理解

    2019-10-30
    赞同 1
    回复 5
    • xt
      xt
      2019-10-30
      好的 第一次写 没太注意
      2019-10-30
      2
      回复
    • TNT
      TNT
      2019-10-30回复xt
      写的挺好的哈。最后的话。建议你写个代码片段。可以让使用的人直接看到效果
      2019-10-30
      回复
    • TNT
      TNT
      2019-10-30回复xt
      然后提个建议,拼接的时候比如:value = curYear + '-' + showMonth + '-' + showDay; 
      可以改为:
      value= `${curYear}-${showMonth}-${showDay}`


      然后后面判断的代码有点冗余了,可以简化下。只是单纯提个建议哈。 老哥牛逼
      2019-10-30
      2
      回复
    • xt
      xt
      2019-10-30回复TNT
      感谢大佬建议 前端萌新 慢慢进步。。。
      2019-10-30
      回复
    • TNT
      TNT
      2019-10-31回复xt
      社会~
      2019-10-31
      回复
  • 理想
    理想
    2021-12-06

    已取用,非常感谢

    2021-12-06
    赞同
    回复
  • 服饰好帮手创始人-谢阳Albert
    服饰好帮手创始人-谢阳Albert
    2020-06-05

    老哥,你这个是官方picker的升级版,建议把picker的一些字段加入,比如disabled等

    disabled: {
      type: Boolean
    },
    

    2020-06-05
    赞同
    回复
  • 林子
    林子
    2019-12-17

    if (curMonth == 2) {
           days = this.setFebDays();
         }

    initColumn方法在2月时候没有天数,可以把setFebDays 天数返回


    2019-12-17
    赞同
    回复 7
    • 温暖的弦 🥭
      温暖的弦 🥭
      2020-02-07
      这位同学,这个应该加在哪里呢,我没有改过来~~
      2020-02-07
      回复
    • 林子
      林子
      2020-02-07回复温暖的弦 🥭
      问题出在initColumn 方法中,其中判断 if (curMonth == 2)。 源代码是this.setFebDays(),但是因为变量还没有赋值完成,所以永远是空值,可以把setFebDays方法加上 return temp; 再修改我之前回复的修改方法
      2020-02-07
      回复
    • 林子
      林子
      2020-02-07
      2020-02-07
      回复
    • 温暖的弦 🥭
      温暖的弦 🥭
      2020-02-07回复林子
      非常感谢~
      2020-02-07
      回复
    • 许全通
      许全通
      2020-02-09
      const---->let
      2020-02-09
      回复
    查看更多(2)
  • *.小涛
    *.小涛
    2019-11-01

    向大佬学习

    2019-11-01
    赞同
    回复 1
    • xt
      xt
      2019-11-01
      新司机 一起交流 !
      2019-11-01
      回复
登录 后发表内容