小程序日历

calendar.wxml

<view class="flex box box-tb box-align-center">
  <view class="calendar pink-color box box-tb">
        <view class="top-handle fs28 box box-lr box-align-center box-pack-center">
            <view bindtap="chooseYearAndMonth" class="date-area">{{curYear || initYear}}年{{curMonth || initMonth}}月<view class="sjx"></view>
            </view>
            <view class="next-handle" bindtap="nowToday" data-handle="next">
                <view>今天</view>
            </view>
        </view>
        <view class="weeks box box-lr box-pack-center box-align-center">
            <view class="flex week fs28" wx:for="{{weeksCh}}" wx:key="{{index}}" data-idx="{{index}}">{{item}}</view>
        </view>
        <view class="days box box-lr box-wrap" bindtouchstart="touchstart" bindtouchmove="touchmove" bindtouchend="touchend">
            <view wx:if="{{hasEmptyGrid}}" class="grid white-color box box-align-center box-pack-center" wx:for="{{empytGrids}}" wx:key="{{index}}" data-idx="{{index}}">
            </view>
            <view class="grid white-color box box-align-center box-pack-center" wx:for="{{days}}" wx:key="{{index}}" data-idx="{{index}}" catchtap="tapDayItem">
              <view style="display:flex;flex-direction:column;" class="day box box-align-center box-pack-center">
                <text class="border-radius {{item.day == dateItem ? (dateItem==initDate&&initYear==curYear&&curMonth==initMonth) ? ‘pink-bg‘ : ‘pink-bg1‘ : ‘‘}}">{{item.day}}</text>
              </view>
            </view>
        </view>
    </view>
    <view class="date-cur">
      <view class="border-date"></view>
      <view class="month-date">{{curMonth || initMonth}}月{{dateItem}}日</view>
      <view class="border-date"></view>
    </view>
    <view class="list-box" wx:if="{{nodeList.length}}">
      <view wx:for="{{nodeList}}">
      
      </view>
    </view>
    <view class="no-data" wx:elif="{{!nodeList.length}}">暂无数据</view>
</view>

<view class="{{showPicker ? ‘f-layer‘ : ‘‘}}">
  <view class="box box-tb s-picker {{showPicker ? ‘showPicker‘ : ‘‘}}">
    <view class="picker-btns box box-lr box-pack-between box-align-center">
      <view class="picker-btn picker-cancel" data-type="cancel" bindtap="tapPickerBtn">取消</view>
      <view class="picker-btn picker-confirm" data-type="confirm" bindtap="tapPickerBtn">确定</view>
    </view>
    <picker-view class="flex" indicator-style="height: 50px;" style="width: 100%; height: 150px;" value="{{pickerValue}}" bindchange="pickerChange">
      <picker-view-column>
        <view class="picker-view" wx:for="{{pickerYear}}" wx:key="*this" style="line-height: 50px">{{item}}年</view>
      </picker-view-column>
      <picker-view-column>
        <view class="picker-view" wx:for="{{pickerMonth}}" wx:key="*this" style="line-height: 50px">{{item}}月</view>
      </picker-view-column>
    </picker-view>
  </view>
</view>

calendar.js

let chooseYear = null;
let chooseMonth = null;
let aboutSlide = null;

const conf = {
  data: {
    hasEmptyGrid: false,
    showPicker: false,
    dateItem: new Date().getDate(),
    initDate: new Date().getDate(),
    initYear: new Date().getFullYear(),
    initMonth: new Date().getMonth() + 1
  },
// 左右滑动start
  touchstart(e) {
        const t = e.touches[ 0 ];
        const startX = t.clientX;
    const startY = t.clientY;
    this.setData({
            initstartX: startX,
            initstartY: startY
        });
    // console.log(this.data.initstartX,this.data.initstartY,‘chushi‘)
    },
    touchmove(e) {
    const t = e.touches[ 0 ];
        const startX = t.clientX;
    const startY = t.clientY;
    this.setData({
            movestartX: startX,
            movestartY: startY
        });
  },
  touchend(e) {
    if(!this.data.movestartX){
      return
    }
    let distanceX = Math.abs(this.data.movestartX - this.data.initstartX)
    let distanceY = Math.abs(this.data.movestartY - this.data.initstartY)
    if(distanceX < 100 || distanceY > distanceX){
      this.setData({
        movestartX: 0
      });
      return
    }
    let curYear = this.data.curYear;
    let curMonth = this.data.curMonth - 1
    // console.log(this.data.movestartX,this.data.initstartX,123)
    if(this.data.movestartX-this.data.initstartX > 100){
      curYear = this.data.curYear;
      curMonth = this.data.curMonth - 1
      if(curMonth < 1){
        curMonth = 12
        curYear = curYear - 1
      }
      if(curYear < 2010){
        this.setData({
          movestartX: 0
        });
        return
      }
      // 正数往右,月份减1
    }
    if(this.data.movestartX-this.data.initstartX < -100){
      curYear = this.data.curYear;
      curMonth = this.data.curMonth + 1
      if(curMonth > 12){
        curMonth = 1
        curYear = curYear + 1
      }
      let maxYear = new Date().getFullYear() + 10;
      if(curYear > maxYear){
        this.setData({
          movestartX: 0
        });
        return
      }
      // 负数往左,月份加1
    }
    if (this._calcDaysFn(curYear, curMonth) < this.data.dateItem){
      this.setData({
        dateItem: this._calcDaysFn(curYear, curMonth)
      })
    }
    this.calculateEmptyGrids(curYear, curMonth);
    this.calculateDays(curYear, curMonth);
    this.setData({
      curYear:curYear,
      curMonth:curMonth
    });
    aboutSlide = null
    // this._myNodeData(curYear,curMonth)
    this.setData({
            movestartX: 0
        });
  },
// 左右滑动end
  onLoad() {
    aboutSlide = null;
    const date = new Date();
    const curYear = date.getFullYear();
    const curMonth = date.getMonth() + 1;
    const weeksCh = [‘周日‘, ‘周一‘, ‘周二‘, ‘周三‘, ‘周四‘, ‘周五‘, ‘周六‘];
    this.calculateEmptyGrids(curYear, curMonth);
    this.calculateDays(curYear, curMonth);
    this.setData({
      curYear,
      curMonth,
      weeksCh
    });
  },
  getThisMonthDays(year, month) {
    return new Date(year, month, 0).getDate();
  },
  getFirstDayOfWeek(year, month) {
    return new Date(Date.UTC(year, month - 1, 1)).getDay();
  },
  calculateEmptyGrids(year, month) {
    const firstDayOfWeek = this.getFirstDayOfWeek(year, month);
    let empytGrids = [];
    if (firstDayOfWeek > 0) {
      for (let i = 0; i < firstDayOfWeek; i++) {
        empytGrids.push(i);
      }
      this.setData({
        hasEmptyGrid: true,
        empytGrids
      });
    } else {
      this.setData({
        hasEmptyGrid: false,
        empytGrids: []
      });
    }
  },
  calculateDays(year, month) {
    let days = [];
    const thisMonthDays = this.getThisMonthDays(year, month);
    for (let i = 1; i <= thisMonthDays; i++) {
      days.push({
        day: i
      });
    }
    this.setData({
      days
    });
  },
  nowToday(e) {
    // console.log(‘今天‘)
    let that = this;
    if(this.data.curYear == new Date().getFullYear() && this.data.curMonth == new Date().getMonth() + 1){
      this.setData({
        dateItem: new Date().getDate()
      });
      return
    }
    this.calculateEmptyGrids(new Date().getFullYear(), new Date().getMonth() + 1);
    this.calculateDays(new Date().getFullYear(), new Date().getMonth() + 1);
    this.setData({
      dateItem: new Date().getDate(),
      curYear: new Date().getFullYear(),
      curMonth: new Date().getMonth() + 1
    })
    aboutSlide = null;
    // this._myNodeData(new Date().getFullYear(),new Date().getMonth() + 1)
  },
  tapDayItem(e) {
    let that = this;
    const idx = e.currentTarget.dataset.idx;
    const days = this.data.days;
    this.setData({
      days,
      dateItem: days[idx].day
    });
    // console.log(this.data.nodeList)
    // console.log(‘点击日历选择第 ‘ + this.data.dateItem+‘ 天‘)
  },
  chooseYearAndMonth() {
    const curYear = this.data.curYear;
    const curMonth = this.data.curMonth;
    let pickerYear = [];
    let pickerMonth = [];
    let maxYear = new Date().getFullYear() + 10;
    for (let i = 2010; i <= maxYear; i++) {
      pickerYear.push(i);
    }
    for (let i = 1; i <= 12; i++) {
      pickerMonth.push(i);
    }
    const idxYear = pickerYear.indexOf(curYear);
    const idxMonth = pickerMonth.indexOf(curMonth);
    this.setData({
      pickerYear,
      pickerMonth
    })
    this.setData({
      pickerValue: [idxYear, idxMonth],
      showPicker: true,
    });
  },
  pickerChange(e) {
    const val = e.detail.value;
    aboutSlide = true
    chooseYear = this.data.pickerYear[val[0]];
    chooseMonth = this.data.pickerMonth[val[1]];
  },
  tapPickerBtn(e) {
    const type = e.currentTarget.dataset.type;
    if(aboutSlide == null){
      chooseYear = this.data.curYear || new Date().getFullYear();
      chooseMonth = this.data.curMonth || new Date().getMonth() + 1;
    }
    const o = {
      showPicker: false,
    };
    // console.log(‘确定日期前‘,this.data.curYear,this.data.curMonth)
    let tempYear = this.data.curYear
    let tempMonth = this.data.curMonth
    if (type === ‘confirm‘) {
      o.curYear = chooseYear;
      o.curMonth = chooseMonth;
      if (this._calcDaysFn(chooseYear, chooseMonth) < this.data.dateItem){
        this.setData({
          dateItem: this._calcDaysFn(chooseYear, chooseMonth)
        })
      }
      this.calculateEmptyGrids(chooseYear, chooseMonth);
      this.calculateDays(chooseYear, chooseMonth);
    }
    // console.log(‘选择确定: ‘ + chooseYear+‘年‘ +chooseMonth+‘月‘+this.data.dateItem+‘日‘)
    this.setData(o);
    if(type === ‘cancel‘){
      return
    }
    // console.log(‘确定日期后,年月相同不调接口‘,this.data.curYear,this.data.curMonth)
    if(this.data.curYear == tempYear && this.data.curMonth == tempMonth){
      return
    }
    // this._myNodeData(chooseYear,chooseMonth)
  },
  _calcDaysFn(year, month) {
    // 计算每个月的最大天数
    if (month == 2) {
      if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0 && year % 4000 != 0)) {
        return 29;
      } else {
        return 28;
      }
    } else {
      if (month == 4 || month == 6 || month == 9 || month == 11) {
        return 30;
      } else {
        return 31;
      }
    }
  }
};

Page(conf);

calendar.wxss

page {
    display: flex;
    flex-direction: column;
    width: 100%;
  background-color: #f3f6fb;
}

.box {
    display: flex;
}

.box-lr {
    flex-direction: row;
}
.f-layer{
  width:100%;
  height:100%;
  position: fixed;
  background: rgba(0, 0, 0, 0.6);
}
.box-tb {
    flex-direction: column;
}
.s-picker{
  position: fixed;
  bottom:0;
  left: 0;
  width:100%;
  background:#fff;
  transition: all .3s;
  transform: translate(0,100%);  
}
.showPicker{
   transform: translate(0,0); 
}
.box-pack-center {
    justify-content: center;
}
.box-pack-between {
    justify-content: space-between;
}
.box-align-center {
    align-items: center;
}
.box-wrap {
    flex-wrap: wrap;
}
.flex {
    flex-grow: 1;
}

.pink-color {
  background-color: #fff;
    color: #666666;
}

.white-color {
    color: #fff;
}
.fs28 {
    font-size: 28rpx;
}
.top-handle {
  width:100%;
    height: 80rpx;
  position:relative;
  line-height: 80rpx;
  box-sizing: border-box;
  border-top:1px solid #eaeaea;
  border-bottom:1px solid #eaeaea;
}
.next-handle{
  position:absolute;
  text-align: center;
  width:110rpx;
  right:0;
  top:0;
}
.date-area {
    height: 80rpx;
    text-align: center;
  color: #666666;
  font-size:28rpx;
  position: relative;
  padding-right:28rpx;
}
.sjx{
  position: absolute;
  right:0;
  top:37rpx;
  width: 0; 
  height: 0; 
  border-left: 8rpx solid transparent; 
  border-right: 8rpx solid transparent; 
  border-top: 8rpx solid #666666;
}
.weeks {
  width:100%;
    height: 50rpx;
    line-height: 50rpx;
  box-sizing: border-box;
  padding-top:60rpx;
  padding-bottom:30rpx;
  color: #0073ff;
  font-size: 28rpx;
}

.week {
    text-align: center;
}

.days {
     min-height: 500rpx; 
   width:750rpx;
}

.grid {
    width: 107.1428571429rpx;
}

.day {
    width: 60rpx;
    min-height: 60rpx; 
    color: #666666;
    font-size: 28rpx;
}
.border-radius{
  height:60rpx;
  width:60rpx;
  text-align: center;
  line-height: 60rpx;
  border-radius: 50%; 
    position: relative;
    left: 0;
    top: 0;
}
.pink-bg {
    color: #fff;
  background-color: #3880f4;
}
.pink-bg1{
  color: #fff;
  background-color: #bec1c5;
}
.date-status{
  display: flex;
  flex-wrap:wrap;
  width:34rpx;
  height:40rpx;
  justify-content: center;
  margin-left:6rpx;  
}
.date-status .wai{
  width:50%;
  height:20rpx;
}
.date-status .wai view{
  height:12rpx;
  width:12rpx;
  border-radius: 50%;
}
.date-status .rg{
  margin-bottom: 18rpx;
}
.spot-com{
  background-color: #73bc23;
}
.spot-yq{
  background-color: #ff4d4d;
}
.spot-wdq{
  background-color: #5c9aff;
}
.spot-com-yq{
  background-color: #ff9b1a;
}
.purple-bg {
    background-color: #b8b8f1;
}
.date-cur{
  width:100%;
  height:80rpx;
  box-sizing: border-box;
  padding:0 53rpx;
  display: flex;
  align-items: center;
  font-size: 24rpx;
}
.border-date{
  height:1px;
  width:210rpx;
  background-color: #eaeaea;
}
.month-date{
  width:224rpx;
  text-align: center;
  color: #999999;
}
.list-box{
  padding:0 30rpx;
  box-sizing: border-box;
}

.picker-btns {
    height: 120rpx;
    line-height: 120rpx;
    border-bottom: 1rpx solid #eee;
}

.picker-confirm {
    margin-right: 50rpx;
}

.picker-cancel {
    margin-left: 50rpx;
}

.picker-view {
    color: #666666;
    text-align: center;
}
.no-data{
  margin-top:100rpx;
  color: #999999;
}

 

小程序日历

上一篇:如何预估服务器带宽需求【转】


下一篇:小程序项目实例