小程序--自定义日期控件(起始时间段选择)

具体的实现效果如下图所示,思路就是利用picker-view自定义实现,对于这种类型的时间选择器,核心点就是对数据的处理,牵扯到数据的初始化以及数据的传递。


设计稿.png

为了更便捷的引用,本次封装采用组件化的模式,具体如下


组件化.png
1: 在此详谈com-date-picker.js

(1) 初始化日期数据

// 初始化日期模态框数据
let date = new Date();
let years = [];
let months = [];
let days = [];

for (let i = date.getFullYear()-10; i <= (date.getFullYear()+10); i++) {
    years.push(String(i))
}
for (let i = 1; i <= 12; i++) {
    months.push(String(i))
}
//后面会根据需求动态改变每月的天数,数组
for (let i = 1; i <= 31; i++) {
    days.push(String(i))
}

(2) 引用页面传递的参数和该界面所需的参数

properties: {
        //开始期间
        startAt: {
             type: String,
            value: "",
            observer: "onStartAt"
        },
        //结束时间
        endAt: {
            type: String,
            value: "",
            observer: "onEndAt"
        },
        isShow: {
            type: Boolean,
            value: false,
            observer: "onDateShow"
        }
    },
    data: {
        years: years,
        months: months,
        days: days,
        startValue:[],
        endValue:[],
        showPicker: false,
        tapIndex: "startTime"
    },

(3) 处理界面传递的参数

methods: {
      onStartAt() {
            this.data.startValue = this.getDateArrWithtime(this.data.startAt,years,months,days);
            days = this.getTotalDayByMonth(this.data.years[this.data.startValue[0]],this.data.months[this.data.startValue[1]]);
        },
        onEndAt() {
            this.data.endValue = this.getDateArrWithtime(this.data.endAt,years,months,days);
        },
        onDateShow() {
            this.setData({
                showPicker: this.data.isShow
            });
        }, 
        //获取月的总天数--数组
        getTotalDayByMonth: function (year, month) {
            month = parseInt(month, 10);
            var d = new Date(year, month, 0);
            let totalDay = d.getDate(); 
            let daySource = [];
            for (let i = 1; i <= totalDay; i++) {
                daySource.push(String(i))
            }
            return daySource;
        },
       //根据时间2019-01-02  得到 ['2019','1','2']
       getDateArrWithtime: function (str, years, months, days) => {
             let arr = [];
             arr = (str).split('-');
             arr[0] = years.indexOf(arr[0]);
             arr[1] = months.indexOf((arr[1].startsWith('0') ? arr[1].substr(1,     arr[1].length) : arr[1]));
             arr[2] = days.indexOf((arr[2].startsWith('0') ? arr[2].substr(1, arr[2].length) : arr[2]));
             return arr;
      }
}

(4) 处理完基本数据之后,进行刷新

      lifetimes: {
        attached: function () { 
            this.setData({
                days: days,
                tapIndex: this.data.tapIndex,
                startValue: this.data.startValue,
                endValue: this.data.endValue
            })
        }
    },

此时就能够初步显示这个时间选择器

(5) 滚动日期的时候,会动态改变显示的起始日期

  methods: {
      bindPickerChange(e) {
            if (this.data.tapIndex == 'startTime') {
                this.data.startValue = e.detail.value;
            } else {
                this.data.endValue = e.detail.value;
            }
            this.calculate();
        },
        calculate() {
            if (this.data.tapIndex == "startTime") {
                let curYear = this.data.years[this.data.startValue[0]];
                let curMonth = this.data.months[this.data.startValue[1]];
                let curDay = this.data.days[this.data.startValue[2]];
                this.data.startAt = curYear+'-'+(curMonth.length==1 ? ('0'+curMonth):curMonth)+'-'+(curDay.length==1 ? ('0'+curDay):curDay);

                this.setData({
                    days: this.getTotalDayByMonth(curYear,curMonth),
                    startAt: this.data.startAt
                })
            } else {
                let endCurYear = this.data.years[this.data.endValue[0]];
                let endCurMonth = this.data.months[this.data.endValue[1]];
                let endCurDay = this.data.days[this.data.endValue[2]];
                this.data.endAt = endCurYear+'-'+(endCurMonth.length==1 ? ('0'+endCurMonth):endCurMonth)+'-'+(endCurDay.length==1 ? ('0'+endCurDay):endCurDay);

                this.setData({
                    days: this.getTotalDayByMonth(endCurYear,endCurMonth),
                    endAt: this.data.endAt,
                })
            }
        }
  }

(6) 点击切换其实时间的tab,会通过调用下面的方法进行刷新界面

  methods: {
      onTapTimeIndex(e) {
            this.data.tapIndex = e.currentTarget.dataset.type;
            if (this.data.tapIndex == "startTime") {
                let curYear = this.data.years[this.data.startValue[0]];
                let curMonth = this.data.months[this.data.startValue[1]];
                days = this.getTotalDayByMonth(curYear,curMonth);
            } else {
                let endCurYear = this.data.years[this.data.endValue[0]];
                let endCurMonth = this.data.months[this.data.endValue[1]];
                days = this.getTotalDayByMonth(endCurYear,endCurMonth);
            }
            this.setData({
                tapIndex: this.data.tapIndex,
                startValue:this.data.startValue,
                endValue:this.data.endValue,
                days: days
            })
        }
  }

(7) 此时基础的数据转换就都实现了,接下来就是要点击完成按钮,将所选择的起始日期传递给所用的界面,具体实现操作如下:

  methods: {
      onSureClick(e) {
            if (new Date(this.data.startAt).getTime() <= new Date(this.data.endAt).getTime()) {
                this.triggerEvent('sureclick', {
                    startAt: this.data.startAt,
                    endAt: this.data.endAt,
                });
            } else {
                utils.showCommonDialog('开始时间不能晚于结束时间');
            }
        }
  }

(8) 点击蒙版,日期选择器会消失,具体实现操作如下:

   methods: {
      onTouchmask: function(event) {
            this.triggerEvent('onTouchmask', {});
      }
  } 
2: 在此详谈com-date-picker.wxss
      @keyframes fade-in {
  0% {
    top: 1000rpx;
    opacity: 0;
  }
  /*初始状态 透明度为0*/
  40% {
    top: 1000rpx;
    opacity: 0;
  }
  /*过渡状态 透明度为0*/
  100% {
    margin-top: 0rpx;
    opacity: 1;
  }
  /*结束状态 透明度为1*/
}
.date-picker {
  position: fixed;
  top: 0;
  left: 0;
  margin: 0;
  padding: 0;
  width: 100%;
  height: 100%;
  z-index: 999;
  animation: fade-in 0.5s ease 1 forwards;
}
.date-picker-mask {
  position: fixed;
  top: 0;
  left: 0;
  bottom: 590rpx;
  background-color: #353535;
  opacity: 0.4;
  width: 100%;
  z-index: 1000;
}
.date-picker-content {
  position: fixed;
  bottom: 0;
  left: 0;
  width: 100%;
  height: 590rpx;
  border-top-left-radius: 16rpx;
  border-top-right-radius: 16rpx;
  background-color: #fff;
  z-index: 9999;
  overflow: hidden;
}
.date-picker-date-content {
  position: relative;
  display: flex;
  height: 160rpx;
  width: 750rpx;
}
.date-picker-date-content-image {
  position: absolute;
  top: 0rpx;
  left: 0rpx;
  width: 100%;
  height: 100%;
}
.date-picker-date-content-bg-left {
  position: absolute;
  top: 0rpx;
  left: 0rpx;
  width: 50%;
  height: 100%;
}
.date-picker-date-content-bg-right {
  position: absolute;
  top: 0rpx;
  right: 0rpx;
  width: 50%;
  height: 100%;
}
.date-picker-date-content-title {
  position: relative;
  color: #333;
  font-size: 26rpx;
  margin-left: 70rpx;
  margin-top: 40rpx;
}
.date-picker-date-content-time {
  position: relative;
  color: #333;
  font-size: 32rpx;
  font-weight: bold;
  margin-left: 70rpx;
  margin-top: 4rpx;
}
.date-picker-content-top {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 80rpx;
  justify-content: space-between;
}
.hover-class {
  background-color: #e6e6e6;
}
.date-picker-content-line {
  background-color: #d3dce6;
  height: 1rpx;
  width: 100%;
  opacity: 0.8;
}
.date-picker-content-cancel {
  line-height: 50rpx;
  height: 50rpx;
  color: #353535;
  padding: 10rpx 48rpx;
  flex: 1; 
  font-size: 28rpx
}
.date-picker-content-sure {
  line-height: 50rpx;
  color: #0096FF;
  height: 50rpx;
  padding: 10rpx 48rpx;
  text-align: right;
  flex: 1; 
  font-size: 28rpx
}
.date-picker-content-center {
  display: flex;
  flex-direction: row;
  align-items: center;
  height: 340rpx;
  overflow: hidden;
  margin-top: 6rpx;
  margin-bottom: 6rpx;
  justify-content: space-between;
}
.date-picker-content-item {
  width: 33.3%;
  height: 350rpx;
  text-align: center;
}
3: 在此详谈com-date-picker.wxml
    <view wx:if="{{showPicker}}" class="date-picker">
    <view class="date-picker-mask" catchtouchstart="onTouchmask"></view>
    <view class="date-picker-content">
        <view class="date-picker-date-content">
            <image src="../../../../image/picker_date_header_{{tapIndex=='startTime'?'left':'right'}}.png" class="date-picker-date-content-image"></image>>
            <view class="date-picker-date-content-bg-left" bindtouchstart="onTapTimeIndex" data-type="startTime">
                <view class="date-picker-date-content-title">开始于</view>
                <view class="date-picker-date-content-time">{{startAt}}</view>
            </view>
            <view class="date-picker-date-content-bg-right" bindtouchstart="onTapTimeIndex" data-type="endTime">
                <view class="date-picker-date-content-title">结束于</view>
                <view class="date-picker-date-content-time">{{endAt}}</view>
            </view>
        </view>
        <view class='date-picker-content-top'>
            <view class="date-picker-content-cancel" ></view>
            <view style="color: #666666; font-size: 28rpx">选择日期</view>
            <view class="date-picker-content-sure"  catchtouchend="onSureClick">完成</view>
        </view>
        <view class="date-picker-content-line"></view>
        <view class="date-picker-content-center">
            <picker-view indicator-style="height: 70rpx;" style="width: 100%; height: 360rpx;" value="{{tapIndex==='startTime'?startValue:endValue}}" catchchange="bindPickerChange">
                <picker-view-column wx:if="{{years.length > 0}}" class="date-picker-content-item">
                    <view wx:for="{{years}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}年</view>
                </picker-view-column>
                <picker-view-column wx:if="{{months.length > 0}}" class="date-picker-content-item">
                    <view wx:for="{{months}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}月</view>
                </picker-view-column>
                <picker-view-column wx:if="{{days.length > 0}}" class="date-picker-content-item">
                    <view wx:for="{{days}}" wx:key="{{index}}" style="line-height: 70rpx">{{item}}日</view>
                </picker-view-column>
            </picker-view>
        </view>
    </view>
</view>
4: 至此,已经完成了日期选择器组建的封装,接下来介绍该如何引用

(1) 在所需要的index.json里

   {
       "usingComponents": {
       "com-date-picker":"../../core/base/components/com-date-picker/com-date-picker"
     }
   }

(2): 在所需要的index.js里

        datePickerIsShow: false,
        startAt: this.getCurrentDate(),
        endAt: this.getCurrentDate()  

        //选择时间
        selectDate: function (e) {
           this.setData({
               datePickerIsShow: true
           });
        }, 
        //获取当前日期
        getCurrentDate: function() {
            var now = new Date();
            var year = now.getFullYear(); //得到年份
            var month = now.getMonth();//得到月份
            var date = now.getDate();//得到日期
            month = month + 1;
            if (month < 10) month = "0" + month;
            if (date < 10) date = "0" + date;
            var time = year + "-" + month + "-" + date;
            return time;
        }

(3): 在所需要的index.wxml里

     <block wx:if="{{datePickerIsShow}}">
        <com-date-picker
                id="date-picker"
                startAt="{{startAt}}"
                endAt="{{endAt}}"
                isShow="{{datePickerIsShow}}"
                bindsureclick="onDatePickerOnSureClick"
                bindonTouchmask="onTouchmask">
        </com-date-picker>
    </block>

5: 到这里起始日期选择器就完成了,如果在初始化起始日期的时候,想往前推一周,自己在网上找方法即可替换,也可调用如下方法解决
(1) 具体方法(moment.js)

    var Moment = function (date) {
       var date;
       if (date) {
          this.date = new Date(date);
       } else {
          this.date = new Date();
       }
       return this;
    };

    Moment.prototype.format = function (format) {
       var date = this.date;
       // var r= /^(\d{4})-(\d{1,2})-(\d{1,2})$/; //正则表达式 匹配出生日期(简单匹配)     
       // r.exec('1985-10-15');
       // s1=RegExp.$1;s2=RegExp.$2;s3=RegExp.$3;//结果为1985 10 15
       if (typeof date === 'string') {
           date = this.parse(date);
       }
    
        var o = {
          "M+": date.getMonth() + 1, //月份 
          "(d+|D+)": date.getDate(), //日 
          "(h+|H+)": date.getHours(), //小时 
          "m+": date.getMinutes(), //分 
          "s+": date.getSeconds(), //秒 
          "q+": Math.floor((date.getMonth() + 3) / 3), //季度 
          "S": date.getMilliseconds() //毫秒 
        };
        var week = {
           "0": "/u65e5",
           "1": "/u4e00",
           "2": "/u4e8c",
           "3": "/u4e09",
           "4": "/u56db",
           "5": "/u4e94",
           "6": "/u516d"
        };
       if (/(y+|Y+)/.test(format)) {
            format = format.replace(RegExp.$1, (date.getFullYear() + "").substr(4 - RegExp.$1.length));
       }
       if (/(E+)/.test(format)) {
            format = format.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? "/u661f/u671f" : "/u5468") : "") + week[date.getDay() + ""]);
       }
       for (var k in o) {
           if (new RegExp("(" + k + ")").test(format)) {
                format = format.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
            }
         }
       return format;
 }

  Moment.prototype.parse = function () {
     return this.date;
  }
  //计算两个日期差差  
  Moment.prototype.differ = function (date) {
      var time1 = this.date.getTime();
      if (typeof date === 'string')
         date = new Date(date);
      var time1 = this.date.getTime();
      var time2 = date.getTime();
      var differ = Math.ceil((time1 - time2) / (1000 * 3600 * 24))
      return differ;
   }

   Moment.prototype.add = function (num, optionType) {
      var date = this.date;
      if ('day' === optionType) {
        date.setDate(date.getDate() + num);
      }
      if ('month' === optionType) {
        date.setMonth(date.getMonth() + num);
      }
      if ('year' === optionType) {
        date.setFullYear(date.getFullYear() + num);
      }
      this.date = date;
      return this;
  }

   module.exports = function (date) {
         return new Moment(date);
   }

(2) 如下调用

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