微信小程序自定义日期时间选择器

最近自己写了一个微信小程序的时间选择器,复用性很高,就分享出来~欢迎指正。

我当前这个可以选择日期,也可以选择日期区间,可以选择上下午,通过配置实现。

效果图:

image
image

首先新建一个component。

.wxml文件内容:

<!-- 自定义时间筛选器 -->
<view hidden="{{!pickerShow}}">
  <view class="picker-container " animation="{{animationData}}">
    <view class="btn-box">
      <view class="pick_btn" bindtap="_pickerHide">取消</view>
      <view class='pick_btn' style="color: #19f" bindtap="_reset">{{config.clear}}</view>
    </view>
    <view class = 'input_time' hidden="{{!config.isTimeFrame}}">
      <view class="view_time">
        <view class = "time_text">开始日期</view>
        <input type="text" class="disable_time {{isStartEnd == 1 ? 'start_active' : ''}}" placeholder="点击选择开始日期" disabled="true"
         placeholder-class="disable-time-placeholder" value="{{startValue}}" bindtap="_getStartValue"/>
      </view>
      <view class="line-time">
        <text>—</text>
      </view>
      <view class="view_time">
        <view class = "time_text">结束日期</view>
        <input type="text" class="disable_time {{isStartEnd == 2 ? 'end_active' : ''}}" placeholder="点击选择结束日期" disabled="true"
        placeholder-class="disable-time-placeholder" value="{{endValue}}" bindtap="_getEndValue"/>
      </view>
    </view>
    <picker-view class='sensorTypePicker' indicator-style='height: 35px;' bindchange="changeDateTime"
      value="{{value}}" bindpickstart="handlePickStart" bindpickend="handlePickEndFirst">
      <picker-view-column style="min-width: 70px;flex-shrink: 0">
        <view class='picker-item' wx:for="{{years}}" wx:key='*this'>{{item}}年</view>
      </picker-view-column>
      <picker-view-column>
        <view class='picker-item' wx:for="{{months}}" wx:key='*this'>{{item}}月</view>
      </picker-view-column>
      <picker-view-column>
        <view class='picker-item' wx:for="{{days}}" wx:key='*this'>{{item}}日</view>
      </picker-view-column>
      <picker-view-column hidden="{{!config.isWeek}}">
        <view class='picker-item' wx:for="{{weeks}}" wx:key='*this'>{{item}}</view>
      </picker-view-column>
    </picker-view>
    <view class='determine-list'>
      <button class="determine-submit-button determine-submit-large" bindtap="onConfirm">确定</button>
    </view>
  </view>
  <!-- 遮罩 -->
  <view class="sensorType-screen" bindtap="hideModal" animation="{{animationOpacity}}"/>
</view>

.js文件

/**
 * 如何使用:
 * 1,在组件.json文件引入
 *   如:"time-picker": "/common/component/timeDataPiker/timeDataPiker"
 * 2,在组件.wxss文件里加入模板
 *   如: <time-picker pickerShow="{{isPickerShow}}" id="picker" 
 *        wx:if="{{isPickerRender}}"config="{{pickerConfig}}" bind:timeData="searchTime"
 *        bind:timeReset="timeReset"></time-picker>
 * 3,在组件js文件的data里加入配置项
 *   isPickerRender: false, 控制组件隐藏显示
 *   isPickerShow: false,   控制组件隐藏显示
 *   pickerConfig: {
 *     isTimeFrame: false,  是否显示开始结束时间框
 *     clear:'清空时间', 重置按钮文本
 *     isWeek:true   是否显示上午下午
 *   }
 * 4,bind:timeData="searchTime" 获取时间 * 5,bind:timeReset="timeReset" 重置时间
 */

var now = new Date();
var yearData = now.getFullYear(); //得到年份
var monthData = now.getMonth();//得到月份
var monthDataRel = now.getMonth()+1;//得到月份
var dayData = now.getDate();//得到日期

Component({

  behaviors: [],

  properties: {
    pickerShow: {
      type: Boolean,
      observer: function (val) {   //弹出动画
        if (val) {
          let animation = wx.createAnimation({
            duration: 500,
            timingFunction: "ease"
          });
          let animationOpacity = wx.createAnimation({
            duration: 500,
            timingFunction: "ease"
          });
          setTimeout(() => {
            animation.bottom(0).step();
            animationOpacity.opacity(0.7).step();
            this.setData({
              animationOpacity: animationOpacity.export(),
              animationData: animation.export()
            })
          }, 0);
        } else {
          let animation = wx.createAnimation({
            duration: 100,
            timingFunction: "ease"
          });
          let animationOpacity = wx.createAnimation({
            duration: 500,
            timingFunction: "ease"
          });
          animation.bottom(-320).step();
          animationOpacity.opacity(0).step();
          this.setData({
            animationOpacity: animationOpacity.export(),
            animationData: animation.export()
          });
        }
        this.setData({
          startValue: '',
          endValue: '',
          timeDataValue: '',
          isSrue: true,
          value: [yearData - 1990, monthData, dayData-1],
        })
      }
    },
    config: {
      type: Object,
      observer(newVal, oldVal, changedPath) {
       
      }
    },
  },


  data: {
    startValue: '', //开始时间
    endValue:'', // 结束时间
    timeDataValue: '', // 不选择开始时间结束时间的时间
    isPicking: false,
    isStartEnd:0,
    isSrue:true
  }, // 私有数据,可用于模板渲染

  lifetimes: {
    // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
    attached: function () {
      this._initTimeArray();
    },
    moved: function () { },
    detached: function () { },
  },

  // 生命周期函数,可以为函数,或一个在methods段中定义的方法名
  attached: function () { }, // 此处attached的声明会被lifetimes字段中的声明覆盖
  ready: function () {
    this._init();
  },

  pageLifetimes: {
    // 组件所在页面的生命周期函数
    show: function () { },
    hide: function () { },
    resize: function () { },
  },

  methods: {
    // 取消
    _pickerHide: function () {
      this.setData({
        pickerShow: false,
      });
    },
    //滚动开始
    handlePickStart: function (e) {
      this.setData({
        isPicking: true
      })
    },
    //滚动结束
    handlePickEndFirst: function (e) {
      this.setData({
        isPicking: false,
      })
    },
    // 监控滑动
    changeDateTime: function (e) {
      this._calculation(e);
    },
    // 重新计算天数
    _calculation: function (e) {
      let year = 1990;
      let month = 1;
      let day = 1;
      let week = '';
      for (let i = 0; i <= e.detail.value.length; i++) {
        if (i == 0) {
          year = year + e.detail.value[i]
        }
        if (i == 1) {
          month = month + e.detail.value[i]
        }
        if (i == 2) {
          day = day + e.detail.value[i]
        }
        
        if (i == 3) {
          if (e.detail.value[i] == 0) {
            week = '—'
          }
          if (e.detail.value[i] == 1) {
            week = '上午'
          }
          if (e.detail.value[i] == 2) {
            week = '下午'
          }
          
        }
        let days = [];
        for (let i = 1; i <= this.getDays(year, month); i++) {
          days.push(i);
        }
        this.setData({
          days,
        })
      }
      this._selectionPeriod(year, month, day, week);
    },
    // 重新计算天数
    getDays: function (year, month) {
      let daysInMonth = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
      if (month === 2) {
        return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0
          ? 29
          : 28;
      } else {
        return daysInMonth[month - 1];
      }
    },
    // 获取默认时间为今日时间
    _init:function() {
      this.setData({
        value: [yearData - 1990, monthData, dayData-1],
      });
    },
    // 初始化时间列表
    _initTimeArray:function() {
      const date = new Date();
      const years = [];
      const months = [];
      const days = [];
      const weeks = ['—', '上午', '下午'];
    
      for (let i = 1990; i <= date.getFullYear()+50; i++) {
        years.push(i)
      }
      for (let i = 1; i <= 12; i++) {
        months.push(i)
      }
      for (let i = 1; i <= 31; i++) {
        days.push(i)
      }

      this.setData({
        years,
        months,
        days,
        weeks
      })
    },
    // 重置
    _reset:function(){
      this.setData({
        endValue: '',
        startValue: '',
        timeDataValue: ''
      })
      if (this.data.config.isTimeFrame) {
        this.setData({
          isSrue: false,
        });
      } else {
        this.triggerEvent('timeReset', { 'timeData': this.data.timeDataValue });
        this.setData({
          pickerShow: false,
        });
      }
     
    },
    // 点击选择开始时间
    _getStartValue: function (e){
      var y = ''
      var m = ''
      var d = ''
      for (let i = 1; i <= this.data.value.length; i++){
        if (i = 1) {
          y = this.data.value[i-1]+1990
        }
        if (i = 2) {
          m = this.data.value[i-1]+1
        }
        if (i = 3) {
          d = this.data.value[i-1]+1
        }
        
      }
      this.setData({
        startValue: y + '-' + m + '-' + d,
        isStartEnd: 1,
      })
    },
    // 点击选择结束时间
    _getEndValue: function(){
      var y = ''
      var m = ''
      var d = ''
      for (let i = 1; i <= this.data.value.length; i++) {
        if (i = 1) {
          y = this.data.value[i - 1] + 1990
        }
        if (i = 2) {
          m = this.data.value[i - 1] + 1
        }
        if (i = 3) {
          d = this.data.value[i - 1] + 1
        }

      }
      this.setData({
        endValue: y + '-' + m + '-' + d,
        isStartEnd: 2,
      })
    },
    // 滑动选择时间
    _selectionPeriod: function (year, mouth, day, week){
      if (this.data.config.isTimeFrame) {
        if (this.data.isStartEnd ==1) {
          this.setData({
            startValue: year + '-' + mouth + '-' + day,
          })
        } else if (this.data.isStartEnd == 2) {
          this.setData({
            endValue: year + '-' + mouth + '-' + day,
          })
        }
      } else {
        this.setData({
          timeDataValue: year + '-' + mouth + '-' + day + '-' + week,
        })
      }
    },
    // 确认
    onConfirm: function(){
      if (this.data.isSrue) {
        if (this.data.isPicking) { return }
        if (this.data.config.isTimeFrame) {
          if (!this.data.startValue) {
            wx.showToast({
              icon: "none",
              title: "请选择开始时间"
            });
            return
          }
          if (!this.data.endValue) {
            wx.showToast({
              icon: "none",
              title: "请选择结束时间"
            });
            return
          }

          var startList = new Date(this.data.startValue);
          var endList = new Date(this.data.endValue);
          if (startList.getTime() <= endList.getTime()) {
            var timeData =
              this.triggerEvent('timeData', { 'startData': this.data.startValue, 'endData': this.data.endValue });
            this.setData({
              pickerShow: false,
            });
          } else {
            wx.showToast({
              icon: "none",
              title: "结束时间不能早于开始时间"
            });
            return
          }
        } else {
          if (!this.data.timeDataValue) {
            this.triggerEvent('timeData', { 'timeData': yearData + '-' + monthDataRel + '-' + dayData + '-' + '—' });
            this.setData({
              pickerShow: false,
            });
          } else {
            this.triggerEvent('timeData', { 'timeData': this.data.timeDataValue });
            this.setData({
              pickerShow: false,
            });
          }
        }
      } else {
        this.triggerEvent('resetConfirm', { 'startData': this.data.startValue, 'endData': this.data.endValue });
        this.setData({
          pickerShow: false,
        });
      }
    
    }
  }
})

.sjon文件

{
  "component": true,
  "usingComponents": {}
}

.wxss文件

.picker-item{
  line-height: 50px;  
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 自定义时间 */
.picker-container {
  display: flex;
  flex-direction: column;
  /* justify-content: center; */
  align-items: center;

  width: 100%;
  overflow: hidden;
  position: fixed;
  bottom: -320px;
  left: 0;
  /* height: 0; */
  transition: height 0.5s;
  z-index: 2000;
  background: white;
  /* border-bottom: 1px solid #E8E8E8; */
}
.sensorType-screen{
  width: 100vw;
  /* height:400rpx; */
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background: #333333;
  opacity: 0;
  overflow: hidden;
  z-index: 1999;
  color: #fff;
}
.sensorTypePicker{
  width: 690rpx;
  height: 130px;
  /* padding: 45px 0; */
}
.picker-item{
  line-height: 50px;  
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 16px;
  /* overflow: hidden; */
}
.box{
   padding: 0 10px; 
}

/* 至 */
.to{
  width:100%;
  display: flex;
  justify-content: center;align-items: center;
  color:rgb(138,138,138);
  font-size: 30rpx;
  /* font-size:30rpx; */
}

.btn-box{
  width: 100%;
  display: flex;
  height: 90rpx;
  justify-content: space-between;
  align-items: center;
  border-bottom: 1px solid #eee;
}
.pick_btn{
  padding: 7px 15px;
  color: #666666;
  /* background-color: #159; */
}


/*输入框中的时间样式*/
.input_time {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  /* border-bottom: 1px solid #eee; */
}
.view_time {
  padding: 24rpx 30rpx;
}
.time_text {
  font-size: 24rpx;
  color: #999;
}
.disable_time {
  font-size: 30rpx;
  background-color: #F0F2F5;
  color: #666;
  margin-top: 20rpx;
  width: 230rpx;
  padding: 12rpx 30rpx;
  border-radius: 6rpx;
}
.disable-time-placeholder{
  color: #999999;
  font-size: 24rpx;
}
.determine-list{
  margin-top: 24rpx;
  width: 94%;
}
.determine-submit-button{
  font-size: 30rpx;
  background: linear-gradient(to bottom,#289CFF,#51CBFF);
  color: #FFFFFF;
  margin-bottom: 36rpx;
}
.determine-submit-button::after{
  border: 0;
}
.determine-submit-large{
  height: 72rpx;
  line-height: 72rpx;
  width: 100%;
  border-radius: 12rpx;
}
.line-time{
  margin-top: 40rpx;
  color: #999999;
}
.start_active, .end_active{
  border:2rpx #289CFF solid;
}

如何使用(从很多代码里截的,粘贴修改可用)

1,打开要使用的page的json文件配置路径

{
  "usingComponents": {
    "time-picker": "/common/component/timeDataPiker/timeDataPiker",
  }
}

2,在wxml文件中引入

<time-picker pickerShow="{{isPickerShow}}"  wx:if="{{isPickerRender}}"
 config="{{pickerConfig}}" bind:timeData="searchTime" bind:timeReset="timeReset"></time-picker>

3,在js文件控制显示

const app = getApp();
var util = require('../../../utils/util.js');
Page({
  /**
   * 页面的初始数据
   */
  data: {
    // 时间控件开始
    isPickerRender: false,
    isPickerShow: false,
    pickerConfig: {
      isTimeFrame: false,
      clear:'清空时间',
      isWeek:true
    },
    // 时间控件结束
},
  
  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {
    
  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {
  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {
    
  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {
    
  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {
  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {
    
  },

  // 按照选择日期搜索
  searchTime: function (e) {
    if (e.detail.timeData){
      let data = e.detail.timeData.split('-')
      var time = ''
      var text = ''
      for(var i in data){
        if (data[i] == '—') {
          time = data[0] + '-' + data[1] + '-' + data[2] + 'T00:00:00' + ',' + data[0] + '-' + data[1] + '-' + data[2] + 'T23:59:59';
          text = data[1] + '-' + data[2]+' '
        }
        if (data[i] == '上午') {
          time = data[0] + '-' + data[1] + '-' + data[2] + 'T00:00:00' + ',' + data[0] + '-' + data[1] + '-' + data[2] + 'T11:59:59';
          text = data[1] + '-' + data[2] + ' ' + data[i]
        }
        if (data[i] == '下午') {
          time = data[0] + '-' + data[1] + '-' + data[2] + 'T12:00:00' + ',' + data[0] + '-' + data[1] + '-' + data[2] + 'T23:59:59'
          text = data[1] + '-' + data[2] + ' ' + data[i]
        }
      }
    }
    this.setData({
      createTime: time,
      timeText: text
    })
    this.getDelivery(5, this.data.inputSuccessValue, this.data.createTime);

  },

 

  // 显示或隐藏时间插件
  pickerShow: function () {
    this.setData({
      isPickerShow: true,
      isPickerRender: true,
    });
  },

  //可送货订单时间插件
  deliveryPickerShow: function() {
    this.setData({
      isDeliveryPickerShow: true,
      isDeliveryPickerRender: true,
      resetDeliveryTime: false
    })
  },
  
  // 清除时间
  timeReset:function(e){
    this.setData({
      createTime: e.detail.timeData
    })
    this.getDelivery(5, this.data.inputSuccessValue, this.data.createTime);
  },
  
  timeDeliveryReset: function(e) {
    this.setData({
      resetDeliveryTime: true
    })
  },

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