美文网首页
如何编写一个类似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