美文网首页
如何编写一个类似Airbnb一样的日历控件

如何编写一个类似Airbnb一样的日历控件

作者: 文子产品笔记 | 来源:发表于2018-09-18 10:00 被阅读0次

    最近由于小程序开发需要用到一个日历类似Airbnb日期选择的日历控件,由于在网上没找到合适的,于是干脆自己写一个,其实并不复杂,下面展示一下效果


    26911CD3-603A-48FB-8CAF-DF63D59788B4.png

    其实这样的效果又一个缺陷,就是由于没有分页的效果,所以一次不能展示无限长时间,我这里展示的是最近一年的所有天数,废话不多说,贴代码了。
    wxml代码:

    <!--index.wxml-->
    <view class="container">
    
      <view class='content'>
        <view class='top_week'>
          <view class='week_text' wx:for='{{weeks_ch}}' wx:key='key' wx:item='{{item}}'>{{item}}</view>
        </view>
    
        <scroll-view scroll-y class='scrollview'>
          <block wx:for='{{dataList}}' wx:key='key' wx:item='{{item}}'>
            <view class='item_title'>
              <view class='item_title_text'>{{item.year}}年{{item.month}}月</view>
            </view>
            <view class='item_data'>
              <block wx:for='{{item.days}}' wx:key='sub_key' wx:for-item='sub_day'>
                <view class="day_item {{sub_day.status==2?'enable_no':''}} {{sub_day.status==1?'cur_data':''}} {{sub_day.select==0?'start_time':''}} {{sub_day.select==2?'center_time':''}} {{sub_day.select==1?'end_time':''}} {{sub_day.select==4?'only_start_time':''}}" data-year="{{item.year}}" data-month="{{item.month}}" data-day="{{sub_day.day}}" data-select="{{sub_day.select}}" data-status="{{sub_day.status}}" bindtap="{{(sub_day.status!=3&&sub_day.status!=2)?'day_click':''}}">{{sub_day.day}}</view>
              </block>
            </view>
          </block>
        </scroll-view>
      </view>
    </view>
    
    

    wcss代码如下:

    .content{
      display: flex;
      flex-direction: column;
      margin-left: 30px;
      margin-right: 30px;
    }
    
    .filter_content{
      display: flex;
      flex-direction: column;
      justify-content: center;
    }
    
    .barview{
      display: flex;
      height: 30px;
      justify-content: center;
    }
    
    .bar{
      position: relative;
      width: 100%;
      height: 30px;
    }
    
    .btn1{
      position: absolute;
    }
    
    .person{
      display: flex;
      height: 30px;
      justify-content: center;
    }
    
    .line-img{
      background: gray;
      width: 100%;
      height: 1px;
    }
    
    .line{
      display: flex;
      justify-content: center;
    }
    
    .kedus{
      width: 24px;
      line-height: 50rpx;
      text-align: center;
      background-size: 24px 30px;
      padding-top: 5rpx;
    }
    
    .no_sel_text{
      color: gray;
      font-size: 12px;
    }
    
    .sel_text{
      color: #fff;
      font-size: 9px;
    }
    
    .kedu{
      display: flex;
      width: 100%;
      justify-content: space-between;
      position: relative;
    }
    
    .kedu_img{
      width: 24px;
      height: 50rpx;
    }
    
    .showview{
      display: flex;
      justify-content: center;
    }
    
    .showtext{
      color: #ff0000;
    }
    
    .space_type_view{
      display: flex;
      flex-direction: row;
      flex-flow: wrap;
    }
    
    .space_type_item{
      width: 30%;
      height: 60rpx;
      border-radius: 30rpx;
      margin-top: 20rpx;
      font-size: 30rpx;
      line-height: 60rpx;
      display:flex;
      justify-content: center;
      text-align: center;
    }
    
    .center_item{
      margin-left: auto;
      margin-right: auto;
    }
    
    .enable_no{
      border: 1rpx solid #6D7C8D;
      color: black;
    }
    
    .enable_yes{
      border: 1rpx solid #E3E3E3;
      color: gray;
    }
    
    .checked_yes{
      background: #6EBB59;
      border: 0rpx;
      color: #fff;
    }
    
    .checked_no{
      border: 1rpx solid #E3E3E3;
    }
    
    .submit{
      position: fixed;
      height:120rpx; 
      width: 100%;
      bottom: 0rpx;
    }
    
    .result_view{
      width: 650rpx;
      height: 90rpx;
      margin-left: auto;
      margin-right: auto;
      margin-top: 15rpx;
      margin-bottom: 15rpx;
      background: #49ae35;
      color: #fff;
      line-height: 90rpx;
      font-size: 32rpx;
      text-align: center;
    }
    
    .title_view{
      margin-top: 30rpx;
      color: #333333;
      font-weight: bold;
    }
    

    js代码如下:

    //index.js
    var data_cal = require("../../utils/data_cal.js");
    
    const app = getApp();
    var cur_data = new Date();
    
    Page({
      data: {
        weeks_ch:['日', '一', '二', '三', '四', '五', '六'],
        dataList:null,
        start_data:null,
        end_data:null
      },
    
      onLoad: function () {
        var year = cur_data.getFullYear();
        var month = cur_data.getMonth()+1;
        var day = cur_data.getDate();
        this.initData(year,month-1);
      },
    
      //初始化日期数据
      initData: function (cur_year, cur_month) {
        var a = [];
        for (var i = 0; i < 12; i++) {
          if (cur_month + 1 > 12) {
            cur_year = cur_year + 1;
            cur_month = 1;
          } else {
            cur_month = cur_month + 1;
          }
          var mObject1 = this.calculateDays(cur_year, cur_month);
          a[i] = mObject1;
        }
        this.setData({
          dataList:a
        });
      },
    
      // 获取当月有多少天(下个月月初是多少)
      getThisMonthDays: function (year, month) {
        return new Date(year, month, 0).getDate();
      },
    
      // 获取当月第一周第一天是周几
      getFirstDayOfWeek: function (year, month) {
        return new Date(Date.UTC(year, month - 1, 1)).getDay();
      },
    
      // 计算当前年月空的几天
      calculateEmptyGrids: function (year, month) {
        const firstDayOfWeek = this.getFirstDayOfWeek(year, month);
        let empytGrids = [];
        if (firstDayOfWeek > 0) {
          for (let i = 0; i < firstDayOfWeek; i++) {
            empytGrids.push(i);
          }
        }
        return empytGrids;
      },
    
      calculateDays: function (year, month) {
        var mObject = {};                               //存入单月对象
        mObject["year"] = year;
        mObject["month"] = month;
    
        var days = [];
        var empytGrids = this.calculateEmptyGrids(year, month);
        for (let i = 0; i < empytGrids.length; i++) {    //把由于星期导致的空白的格子数添加进去
          var day = {};
          day["day"] = "";
          day["status"] = 3;
          day["select"] = 3;
          days.push(day);
        }
        var thisMonthDays = this.getThisMonthDays(year, month);//这个月有多少天
        //当前的时间
        var cusDate = new Date(cur_data.getFullYear(), cur_data.getMonth(),cur_data.getDate());
        for (let i = 1; i <= thisMonthDays; i++) {
          var day = {};
          //加入的时间
          var date = new Date(year, month - 1, i);
          //status 0-可选择(今后时间)  1-当前时间(今天)  2-不可被选择(过去时间)  3-空白格
          //select 0-开头  1-结尾  2-中间  3-正常  4-只选择一个开始日期
          day["day"] = i;
          day["select"] = 3;
          var time = parseInt(data_cal.calculateTime(date, cusDate));
          if (time < 0) {                      //比现在的时间比较是大于还是小于,小于则不可点击
            day["status"] = 0;
          } else if (time == 0) {
            day["status"] = 1;
          } else {
            day["status"] = 2;
          }
          days.push(day);
        }
        mObject["days"] = days;
        return mObject;
      },
    
      //日期点击事件
      day_click:function(e){
        var obj = {};
        obj.year = e.currentTarget.dataset.year;
        obj.month = e.currentTarget.dataset.month;
        obj.day = e.currentTarget.dataset.day;
        obj.select = e.currentTarget.dataset.select;
        obj.status = e.currentTarget.dataset.status;
    
        if (this.data.start_data == null && this.data.end_data==null){           //开始时间
          this.resetData(obj, null, this.data.dataList,0);
        } else if (this.data.end_data == null && this.data.start_data != null){  //结束时间
          var start = new Date(this.data.start_data).getTime();
          var end_str = obj.year + "-" + obj.month + "-" + obj.day
          var end = new Date(end_str).getTime();
          if (end == start) {
            this.resetData(null, obj, this.data.dataList, 1);
          }else if(end<=start){
            this.clearData(this.data.dataList);
            this.resetData(obj, null, this.data.dataList,0);
          }else{
            this.resetData(null, obj, this.data.dataList,0);
          }
        } else if (this.data.end_data != null && this.data.start_data != null){  //重复开始
          this.clearData(this.data.dataList);
          this.resetData(obj, null, this.data.dataList,0);
        }
      },
    
      //清除日期格式
      clearData: function (data){
        this.setData({
          end_data: null,
          start_data:null
        });
        for (var i = 0; i < data.length; i++) {
          var d = data[i];
          var days = d.days;
          for (var j = 0; j < days.length; j++) {
            var day = days[j];
            day.select = 3;
          }
        }
        this.setData({
          dataList: data
        });
      },
    
      //传入开始时间和结束时间和日期数组
      resetData:function(startData,endData,data,types){
        if(types == 1){
          this.setData({
            end_data: endData.year + "-" + endData.month + "-" + endData.day
          });
        }else{
          if (startData == null && endData != null){
            this.setData({
              end_data: endData.year + "-" + endData.month + "-" + endData.day
            });
            var start = new Date(this.data.start_data).getTime();
            var end = new Date(this.data.end_data).getTime();
            for (var i = 0; i < data.length; i++) {
              var d = data[i];
              var days = d.days;
              for (var j = 0; j < days.length; j++) {
                var day = days[j];
                var timeStr = d.year + "-" + d.month + "-" + day.day;
                var time = new Date(timeStr).getTime();
                if (time == start) {
                  if(day.status!=3){
                    day.select = 0;
                  }
                }else if (time > start && time < end) {
                  day.select = 2;
                } else if (time == end && day.day=="") {
                  day.select = 2;
                } else if (time == end){
                  day.select = 1;
                  break;
                }
              }
            }
          } else if (startData != null && endData == null){
            this.setData({
              start_data: startData.year + "-" + startData.month + "-" + startData.day
            });
            for (var i = 0; i < data.length; i++) {
              var d = data[i];
              if (d.year == startData.year && d.month == startData.month){
                var days = d.days;
                for(var j=0;j<days.length;j++){
                  var day = days[j];
                  if (day.day == startData.day){
                    day.select = 4;
                    break;
                  }
                }
              }
            }
          }
          this.setData({
            dataList: data,
          });
        }
      }
    })
    
    

    简单的日历选择控件就写出来了,很多时候看起来复杂,其实写得时候发现很简单,只要写出第一行代码就可以。

    相关文章

      网友评论

          本文标题:如何编写一个类似Airbnb一样的日历控件

          本文链接:https://www.haomeiwen.com/subject/eibjnftx.html