微信小程序多月份日期多选防酒店日期选择插件

By | 2021年1月15日

微信小程序开发现在很火,在日益增长的需求上,也衍生了很多实用插件,本文介绍一个我自己写的日期多选插件,实现后的效果如下图:

实现方式如下:

一、wxml文件:

<scroll-view class="container" >
  <!--------周列表---------->
  <view class="week-list">
    <view wx:for="{{week}}" wx:key="fweek" class="week">
      {{item}}
    </view>
    <view class="clear"></view>
  </view>
  <view style="height: 2.4rem;"></view>
  <!--------月列表---------->
  <view wx:for="{{showYear}}" wx:key="fyear" wx:for-index="mk" wx:for-item="ylist" class="month-list">
    <view class="year-month">
      {{showYear[mk]}}年{{showMonth[mk]}}月
    </view>
    <view class="month-daybox">
      <view wx:for="{{firstWeek[mk]}}" wx:key="ffk" wx:for-index="ffk" wx:for-item="fflist" class="month-day"></view>
      <view wx:for="{{showMonthDays[mk]}}" wx:key="fmd" wx:for-index="mdk" wx:for-item="daylist" class="month-day {{mk == 0 && today > daylist?'disabled':(canChooseNum>1?(canChooseTimes[showMonthDaysTimestamp[mk][mdk]] == 1?'':'disabled'):'')}} {{continuityChoose[0] == showMonthDaysTimestamp[mk][mdk]||continuityChoose[1] == showMonthDaysTimestamp[mk][mdk]?'act':''}} {{continuityChoose.length >= 2&&sectionDays[showMonthDaysTimestamp[mk][mdk]] == 1?'act-ctniu':''}}" bindtap="{{mk == 0 && today > daylist?'':(canChooseNum>1?(canChooseTimes[showMonthDaysTimestamp[mk][mdk]] == 1?'clickDays':''):'clickDays')}}" data-date="{{showYear[mk]}}-{{showMonth[mk]}}-{{daylist}}">
        <view class="tip-box" style="{{tipPosition}}{{clickThat == showMonthDaysTimestamp[mk][mdk]&&continuityChoose.length==1?'display: block;':''}}">
          <view>请选择离店日期</view>
          <view>如需当日离店,请再次点击入住日期</view>
        </view>
        <view class="tip-triangle" style="{{clickThat == showMonthDaysTimestamp[mk][mdk]&&continuityChoose.length==1?'display: block;':''}}"></view>
        <view wx:if="{{mk == 0 && today == daylist}}" class="today-sign">今天</view>
        <view wx:else  class="today-sign"></view>
        <view>{{daylist}}</view>
        <view wx:if="{{continuityChoose[0] == showMonthDaysTimestamp[mk][mdk]&&continuityChoose[1] != showMonthDaysTimestamp[mk][mdk]}}" class="today-sign">入住</view>
        <view wx:elif="{{continuityChoose[1] == showMonthDaysTimestamp[mk][mdk]&&continuityChoose[0] != showMonthDaysTimestamp[mk][mdk]}}" class="today-sign">离店</view>
        <view wx:elif="{{continuityChoose[0] == showMonthDaysTimestamp[mk][mdk]&&continuityChoose[1] == showMonthDaysTimestamp[mk][mdk]}}" class="today-sign">住/离</view>
        <view wx:else  class="today-sign"></view>
      </view>
      <view class="clear"></view>
    </view>
  </view>
</scroll-view>

二、js文件:

//index.js
//获取应用实例
const App = getApp()
Page({
  data: {
    week : ['日','一','二','三','四','五','六'],
    showYear : [],
    showMonth : [],
    showMonthDays : [],
    showMonthDaysTimestamp : [],
    firstWeek : [],
    today : 0,
    //连续选择
    continuityChoose : [],
    //连续选择区间时间戳
    sectionDays : {},
    winWidth : 0,
    tipPosition : '',
    clickThat : '',
    //一选择天数
    chooseDays : 0,
    currentPages : [],
    //限制选择天数(为0时不限制)
    initChooseNum : 10,
    canChooseNum : 0,
    canChooseTimes : {}
  },
  onLoad: function () {
    let that = this
    that.dateInit(2);
    wx.getSystemInfo({
      success(res) {
        that.setData({
          winWidth: res.windowWidth
        })
      }
    })
    let pages = getCurrentPages();
    that.setData({
      currentPages : pages
    })
    //初始化日期选项
    let chooseDateObj = wx.getStorageSync(App.ccId+'_chooseDateObj')
    if(chooseDateObj){
      that.setData(chooseDateObj)
    }
  },
  /**
   * 初始化日历数据
   * @param {number} showNum - 显示月份数
   */
  dateInit: function (showNum) {
    const date = new Date();
    var showNum = showNum?showNum:1
    var year = date.getFullYear()
    var month = date.getMonth() + 1
    var day = date.getDate()
    var showYear = [],showMonth = [],showMonthDays = [],showMonthDaysTimestamp = [],firstWeek = [];
    for(var i = 0;i&lt;showNum;i++){
      if(month+1&gt;12){
        //目标月天数
        var dayNums = new Date(year, month-1, 0).getDate();
        //目标月第一天周几
        var firstDayWeek = new Date(year, month-1, 1).getDay();
        showYear.push(year);
        showMonth.push(month);
        var monthDays = [];
        var monthDaysTimestamp = [];
        for(var j = 1;j &lt;= dayNums; j++){
          monthDays.push(j)
          monthDaysTimestamp.push(new Date(year+'/'+month+'/'+j).getTime()/1000)
        }
        showMonthDays.push(monthDays);
        showMonthDaysTimestamp.push(monthDaysTimestamp);
        var fdweekArr = [];
        for(var k = 0;k&lt;firstDayWeek;k++){
          fdweekArr.push('');
        }
        firstWeek.push(fdweekArr);
        month = 1;
        year++;
      }else{
        //目标月天数
        var dayNums = new Date(year, month, 0).getDate();
        //目标月第一天周几
        var firstDayWeek = new Date(year, month-1, 1).getDay();
        showYear.push(year);
        showMonth.push(month);
        var monthDays = [];
        var monthDaysTimestamp = [];
        for(var j = 1;j &lt;= dayNums; j++){
          monthDays.push(j)
          monthDaysTimestamp.push(Number(new Date(year+'/'+month+'/'+j).getTime())/1000)
        }
        showMonthDays.push(monthDays);
        showMonthDaysTimestamp.push(monthDaysTimestamp);
        var fdweekArr = [];
        for(var k = 0;k&lt;firstDayWeek;k++){
          fdweekArr.push('');
        }
        firstWeek.push(fdweekArr);
        month++;
      }
    }
    this.setData({
      showYear : showYear,
      showMonth : showMonth,
      showMonthDays : showMonthDays,
      showMonthDaysTimestamp : showMonthDaysTimestamp,
      firstWeek : firstWeek,
      today : day
    })
    // console.log(showYear);
    // console.log(showMonth);
    // console.log(showMonthDays);
    // console.log(firstWeek);
     //console.log(showMonthDaysTimestamp);
  },
  //日期点击事件
  clickDays : function(e){
    let that = this
    let nowDate = e.currentTarget.dataset.date
    let continuityChoose = that.data.continuityChoose
    let continuityChooseVal = []
    let tipPosition = '';
    let nowTimestamp = new Date(nowDate.replace(/-/g, '/')).getTime()/1000
    let chooseDays = 0;
    let sectionDays = {};
    let offsetLeft = e.currentTarget.offsetLeft
    let winWidth = that.data.winWidth
    if(continuityChoose.length == 0 || continuityChoose.length &gt;= 2){
      tipPosition = that.setTipPosition(offsetLeft,winWidth);
      continuityChooseVal = [nowTimestamp];
      that.limitSelectionDays(nowTimestamp)
    }else if(continuityChoose.length == 1){
      continuityChooseVal = continuityChoose
      //判断当前已选日期是否早于当前点击日期
      let hasTimestamp = continuityChoose[0]
      if(nowTimestamp&lt;hasTimestamp){
        tipPosition = that.setTipPosition(offsetLeft,winWidth);
        continuityChooseVal = [nowTimestamp]
        that.limitSelectionDays(nowTimestamp)
      }else{
        continuityChooseVal.push(nowTimestamp);
        chooseDays = nowTimestamp-continuityChooseVal[0]
        if(chooseDays &gt; 0){
          chooseDays = Math.ceil(chooseDays/(24*3600))+1
          if(chooseDays &gt; 2){
            let startSectionTime = continuityChooseVal[0]
            for(let i = 0;i &lt; chooseDays-2; i++){
              startSectionTime+=(24*3600)
              sectionDays[startSectionTime] = 1
            }
          }
        }else{
          chooseDays+=1;
        }
        that.setData({
          canChooseTimes : {},
          canChooseNum : 0
        })
      }
    }
    that.setData({
      continuityChoose : continuityChooseVal,
      tipPosition : tipPosition,
      clickThat : nowTimestamp,
      sectionDays : sectionDays,
      chooseDays : chooseDays
    })
    if(continuityChooseVal.length&gt;=2){
      setTimeout(function(){
        if(that.data.currentPages.length&lt;=1){
          return false;
        }
        wx.setStorageSync(App.ccId+'_chooseDateObj', {
          continuityChoose : continuityChooseVal,
          sectionDays : sectionDays,
          chooseDays : chooseDays
        })
        let url = '/'+that.data.currentPages[0].route;
        wx.reLaunch({
          url: url
        })
      },1000)
    }
  },
  //设置tip位置
  setTipPosition : function(offsetLeft,winWidth){
    let tipPosition = '';
    if(offsetLeft&gt;winWidth/2){
      if((winWidth-offsetLeft)/2 &lt; 63){
        tipPosition = 'right: 0;';
      }else{
        tipPosition = 'left: 50%;transform: translateX(-50%);';
      }
    }else{
      if(offsetLeft &lt; 63){
        tipPosition = 'left: 0;';
      }else{
        tipPosition = 'left: 50%;transform: translateX(-50%);';
      }
    }
    return tipPosition;
  },
  //将限制选择的天数之后全部设置为不可点状态(及列出可选日期时间戳)
  limitSelectionDays : function(ntime){
    let canChooseNum = this.data.initChooseNum
    let canChooseTimes = {}
    if(canChooseNum&gt;=2){
      for(let i=0;i&lt;canChooseNum;i++){
        canChooseTimes[ntime] = 1;
        ntime=ntime+(24*3600)
      }
    }
    this.setData({
      canChooseTimes : canChooseTimes,
      canChooseNum : canChooseNum
    });
  }
})

三、wxss文件:

.week-list{
  position: fixed;
  z-index: 3;
  top: 0;
  left: 0;
  right: 0;
  height: 2.4rem;
  line-height: 2.4rem;
  background-color: #ffffff;
}
.week-list .week{
  float: left;
  width: 14.2%;
  text-align: center;
}
.month-list{
  padding: 1rem;
  padding-top: 0;
  background-color: #ffffff;
}
.month-list .month-day{
  position: relative;
  float: left;
  width: 14.2%;
  height: 2.6rem;
  padding: 0.2rem 0;
}
.month-list .month-day.act{
  background-color: #FFD428;
}
.month-list .month-day.act-ctniu{
  background-color: #f9e4ab;
}
.month-list .month-day .tip-box{
  display: none;
  position: absolute;
  white-space: nowrap;
  top: -2.6rem;
  background-color: rgba(0,0,0,.5);
  padding: 0.2rem 0;
  width: 10.4rem;
  border-radius: 0.3rem;
  z-index: 2;
  height: 1.6rem;
  pointer-events:none;
  font-weight: 400;
}
.tip-triangle{
  display: none;
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  top: -0.6rem;
  width: 0px;                 /*  宽高设置为0,很重要,否则达不到效果 */
  height: 0px;
  border: 0.3rem solid rgba(0,0,0,.5);
  border-bottom-color: transparent;    /* 设置透明背景色 */
  border-left-color: transparent;
  border-right-color: transparent;
}
.month-list .month-day .tip-box view{
  font-size: 0.6rem;
  height: 0.8rem;
  line-height: 0.8rem;
  color: #ffffff;
}
.month-list .month-day.disabled view{
  color: #999999;
}
.month-list .month-day view{
  text-align: center;
  font-weight: 500;
  height: 1rem;
  line-height: 1rem;
}
.month-list .month-day .today-sign{
  font-size: 0.6rem;
  font-weight: 400;
  height: 0.8rem;
  line-height: 0.8rem;
}
.month-list .year-month{
  text-align: center;
  line-height: 2rem;
}

以上代码实现功能可能会和你想要的结果有出入,但可以进行修改后达到您想要的需求,其实不难。