WX小程序自己封装的时间选择器组件

133 阅读3分钟
//js代码
//util.js文件中的方法

  // 获取年月日  getDate(flag){    let date = new Date();    if(flag){      date = new Date(date.getTime() + 24*60*60*1000);    }    let year = date.getFullYear();    let month = date.getMonth() + 1;    let day = date.getDate();    if (month < 10) {        month = "0" + month;    }    if (day < 10) {        day = "0" + day;    }    let nowDate = year + "-" + month + "-" + day;    return nowDate;  },

  // 获取年月日 N天后日期  getNDate(str,n){    let date = str ? new Date(str) :  new Date();    let newdate = new Date(date.getTime() + n*24*60*60*1000);    let year = newdate.getFullYear();    let month = newdate.getMonth() + 1;    let day = newdate.getDate();    if (month < 10) {        month = "0" + month;    }    if (day < 10) {        day = "0" + day;    }    let nowDate = year + "-" + month + "-" + day;    return nowDate;  }
/*timePicker.js文件代码 *//* **  *时间选择器组件 **  *属性: **      title     选择器title 默认为"选择日期" **      asyncTiem 同步选择器时间 默认为当前时间 **      pattern   时间选择器的模式, **                pattern=0,是普通的模式,当前时间上下1970-2050年的是所选范围 **                pattern=1,是当前时间到未来60天的所选范围 **  *方法: **      determine()  确定点击事件向父组件传值(eventTiem) **      bindDateChange()  打开时间组件的方法 **      onAsyncTiem()   同步时间的方法的方法,不调用默认为"2021-01-01"和asyncTiem属性一起使用
 **
 **  *2021.6.11 */

const util = require("../../utils/util");let date = new Date();let asyncTiem = `${date.getFullYear()}-${date.getMonth()+1}-${date.getDate()}`;Component({  /**   * 组件的属性列表   */  properties: {    //选择器title    title: {      type: String,      value: "选择日期"    },    //同步选择器时间    asyncTiem: {      type: String,      value: asyncTiem,    },    //时间选择器的模式,pattern=0,是普通的模式,当前时间上下1970-2050年的是所选范围    //               pattern=1,是当前时间到未来60天的所选范围    pattern: {      type: Number,      value: 0    }  },  /**   * 组件的初始数据   */  data: {    tiem: '',    isshow: false,    isicon: false,    years: [],    year: date.getFullYear(),    months: [],    month: 2,    days: [],    day: 2,    value: [11, 0, 0],    animationData: {},  },  /**   * 组件的方法列表   */  methods: {    //打开动画    fadeIn: function () {      this.animation.translateY(0).step()      this.setData({        animationData: this.animation.export() //动画实例的export方法导出动画数据传递给组件的animation属性      })    },    //关闭动画    fadeDown: function () {      this.animation.translateY(300).step()      this.setData({        animationData: this.animation.export(),      })    },    //打开组件方法    bindDateChange() {      let that = this;      this.setData({        isshow: true,        isicon: true      })      let animation = wx.createAnimation({        duration: 600, //动画的持续时间   数值越大,动画越慢   数值越小,动画越快        timingFunction: 'ease', //动画的效果 默认值是linear      })      this.animation = animation      setTimeout(function () {        that.fadeIn(); //调用显示动画      }, 200)    },    // 关闭组件    close(e) {      //self点击蒙版外防止穿透      let self = e.target.dataset.ref;      let that = this;      if (self == 'self') {        that.setData({          isicon: false        })        let animation = wx.createAnimation({          duration: 400, //动画的持续时间 默认800ms   数值越大,动画越慢   数值越小,动画越快          timingFunction: 'ease', //动画的效果 默认值是linear        })        this.animation = animation        that.fadeDown(); //调用隐藏动画           setTimeout(function () {          that.setData({            isshow: false          })        }, 400) //先执行下滑动画,再隐藏模块      }    },    //滚动年月计算当前年月下的天数方法    bindChange(e) {      const val = e.detail.value      this.setData({        value: val,        year: this.data.years[val[0]],        month: this.data.months[val[1]],        day: this.data.days[val[2]],      })      //根据切换年份和月份计算天数      let dayNum = new Date(this.data.year, this.data.month, 0).getDate();      //暂存天数的数组      let dayArrs = []      // 天的默认值      let j = 1;      // 如果当前选中的月份是所有月份的第一个月  则日的第一天是当前初始化日的第一日      if (this.data.months[val[1]] == this.data.months[0]) {        j = dayArr[0];      }      // 如果当前选中的月份是最后一个月,则日的最后一天是当前初始化日的最后一日      if (this.data.months[val[1]] == this.data.months[this.data.months.length - 1]) {        dayNum = after60dayArr[2];      }      for (let i = j; i <= dayNum; i++) {        dayArrs.push(i)      }      //修改天数的数组      this.setData({        days: dayArrs,      })      //滚动同日期步      let {        year,        month,        day      } = this.data;      let Cmonth = month < 10 ? '0' + month : month;      let Cday = day < 10 ? '0' + day : day;      let tiem = `${year}-${Cmonth}-${Cday}`      this.setData({        tiem: tiem,      })    },    //确定按钮    determine() {      let {        year,        month,        day      } = this.data;      let Cmonth = month < 10 ? '0' + month : month;      let Cday = day < 10 ? '0' + day : day;      let tiem = `${year}-${Cmonth}-${Cday}`      this.setData({        isshow: false,        tiem: tiem,      })      // 向父组件传值      this.triggerEvent('eventTiem', this.data.tiem)    },    //同步外面传过来的时间    onAsyncTiem() {      let asyncTiem = this.properties.asyncTiem;      let {        years,        months,        days      } = this.data      let asyncTiemArr = asyncTiem.split("-");      let yearsIinde = years.findIndex((item) => {        return item == asyncTiemArr[0]      })      let monthsIinde = months.findIndex((item) => {        return item == asyncTiemArr[1]      })      let daysIinde = days.findIndex((item) => {        return item == asyncTiemArr[2]      })      if (yearsIinde != -1 && monthsIinde != -1 && daysIinde != -1) {        let newValue = [yearsIinde, monthsIinde, daysIinde]        let year = this.data.years[yearsIinde];        let month = this.data.months[monthsIinde];        let day = this.data.days[daysIinde];        this.setData({          value: newValue,          tiem: asyncTiem,          year,          month,          day        })      } else {        throw new Error("所填时间不在该选择器中")      }    },  },  lifetimes: {    // 在组件实例进入页面节点树时执行    attached: function () {      let pattern = this.properties.pattern;      // 初始化时间组件      let years = []      let months = []      let days = []      if (pattern == 1) {        // 获取当前日期下一天        let dates = util.getDate(true);        let dateArr = dates.split("-").map(i => i * 1);        // 获取当前日期下一天的后60天的日期        let after60day = util.getNDate('', 61);        let after60dayArr = after60day.split("-").map(i => i * 1);        years = [dateArr[0]]        // 如果结束年份大约当前年份 则添加结束年份        if (after60dayArr[0] > dateArr[0]) {          years.push(after60dayArr[0]);        }        // 如果开始月份和结束月份是连续月份 则直接加入月份数组 否则跨年怎分为年前和年后        if (dateArr[1] < after60dayArr[1]) {          for (let i = dateArr[1]; i <= after60dayArr[1]; i++) {            months.push(i)          }        } else {          for (let i = dateArr[1]; i <= 12; i++) {            months.push(i)          }          for (let i = 1; i <= after60dayArr[1]; i++) {            months.push(i)          }        }        //根据切换年份和月份计算天数        let dayNum = new Date(dateArr[0], dateArr[1], 0).getDate();        //暂存天数的数组        let dayArr = []        for (let i = dateArr[2]; i <= dayNum; i++) {          dayArr.push(i)        }        days = dayArr;        //默认走0      } else {        for (let i = 1970; i <= 2050; 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      })    },  }})


<!--timePicker.wxml文件代码-->
<!--components/timePicker/timePicker.wxml--><!-- 组件picker --><view class="picker" wx:if="{{isshow}}" data-ref='self' catchtap="close">  <view class="wrap" animation="{{animationData}}">    <image src="../../common/image/xiajiantou.png" wx:if="{{isicon}}" catchtap="close" data-ref='self'></image>    <image src="../../common/image/shangjiantou.png" wx:if="{{!isicon}}"></image>    <view class="selectdate">      {{title}}    </view>    <!-- 选择器 -->    <view class="date">      <view class="xian">        <view class="xian1"></view>        <view class="xian2"></view>      </view>      <picker-view        indicator-style="width: 100%;height: 50px; font-size: 60px;  color: #6A6A6A;   background: rgba(243, 243, 243, 0.2);"        style="width: 100%; height: 280rpx;" value="{{value}}" indicator-class="indicator" bindchange="bindChange">        <picker-view-column>          <view wx:for="{{years}}" wx:key="*this" class="{{index==value[0]?'active  year':'size onyear'}}">            {{item}}            <View class="company">              年            </View>          </view>        </picker-view-column>        <picker-view-column>          <view wx:for="{{months}}" wx:key="*this" class="{{index==value[1]?'active  month':'size onmonth'}}">            {{item>9?item:"0"+item}}            <View class="company">              月            </View>          </view>        </picker-view-column>        <picker-view-column>          <view wx:for="{{days}}" wx:key="*this" class="{{index==value[2]?'active  day':'size onday'}}">            {{item>9?item:"0"+item}}            <View class="company">              日            </View>          </view>        </picker-view-column>      </picker-view>    </view>    <!-- 按钮 -->    <view class="btn_determine" bindtap="determine">      确定    </view>  </view></view>

/* timePicker.wxss *//* components/timePicker/timePicker.wxss */.picker {  width: 100vw;  height: 100vh;  position: fixed;  top: 0rpx;  left: 0rpx;  background: rgba(0, 0, 0, 0.5);  z-index: 9999;}.picker .wrap {  bottom: 0rpx;  position: absolute;  width: 100vw;  height: 580rpx;  background: #FFFFFF;  border-radius: 40rpx 40rpx 0rpx 0rpx;}.picker .wrap image {  display: block;  width: 24rpx;  height: 8rpx;  margin: 22rpx auto 34rpx auto;}.picker .wrap .selectdate {  width: 150rpx;  height: 50rpx;  font-size: 36rpx;  font-family: PingFangSC-Regular, PingFang SC;  font-weight: 400;  color: #6A6A6A;  line-height: 50rpx;  margin-left: 40rpx;  margin-bottom: 10rpx;}.picker .wrap .date .active .company {  margin-left: -20rpx;  display: inline-block;  font-size: 24rpx;  color: #6A6A6A;  font-family: PingFangSC-Regular, PingFang SC;  font-weight: 400;}.picker .wrap .date .size .company {  margin-left: -8rpx;  display: inline-block;  font-size: 24rpx;  color: #6A6A6A;  font-family: PingFangSC-Regular, PingFang SC;  font-weight: 400;}.picker .wrap .date .size {  line-height: 50px;  font-size: 36rpx;  font-family: PingFangSC-Regular, PingFang SC;  font-weight: 400;  color: #9B9B9B;}.picker .wrap .date .year {  margin-left: 70rpx;}.picker .wrap .date .onyear {  margin-left: 135rpx;}.picker .wrap .date .month {  margin-left: 100rpx;}.picker .wrap .date .onmonth {  margin-left: 130rpx;}.picker .wrap .date .day {  margin-left: 70rpx;}.picker .wrap .date .onday {  margin-left: 100rpx;}.picker .wrap .date .active {  line-height: 50px;  font-size: 60rpx;  font-family: PingFangSC-Regular, PingFang SC;  font-weight: 400;  color: #6A6A6A;  letter-spacing: 1px;}.picker .wrap .date .xian {  width: 100%;  height: 24rpx;  position: absolute;  top: 266rpx;}.picker .wrap .date .xian .xian1 {  position: absolute;  left: 290rpx;  background: #6A6A6A;  width: 4rpx;  height: 24rpx;}.picker .wrap .date .xian .xian2 {  position: absolute;  left: 510rpx;  background: #6A6A6A;  width: 4rpx;  height: 24rpx;}.picker .wrap .btn_determine {  width: 240rpx;  height: 80rpx;  line-height: 80rpx;  background: #FF7474;  box-shadow: 0rpx 2rpx 8rpx 0rpx #D5D4D4, 0rpx -2rpx 4rpx 0rpx #C65050, 0rpx 2rpx 4rpx 0rpx #FFCCCC;  border-radius: 40rpx;  margin: 80rpx auto 0 auto;  font-size: 40rpx;  font-family: PingFangSC-Semibold, PingFang SC;  font-weight: 600;  color: #FFFFFF;  text-align: center;}


//调用
//.json引入
{
  "usingComponents": {    "timePicker": "/components/timePicker/timePicker"  },}
//.wxml使用
<!-- 组件picker --><timePicker id="timePicker" bind:eventTiem="onGetTiem" asyncTiem="{{currentTimeNext}}" pattern="1"></timePicker>//.js中注入
Page({/**   * 页面的初始数据  */data: {    tiem: '',
}
bindDateChange(){    //打开时间组件的方法    this.timePicker.bindDateChange()    //同步时间的方法    this.timePicker.onAsyncTiem()  },  onGetTiem(e){    let tiem=e.detail    this.setData({      tiem    })    }, /**   * 生命周期函数--监听页面初次渲染完成   */  onReady: function () {    //调用时间选择器组件,使用其方法    this.timePicker = this.selectComponent('#timePicker');  },
}

效果图: