微信小程序结合日历判断累计打卡以及连续打卡

参考文档:https://blog.csdn.net/qq_38137411/article/details/81319299

写在前面

新的小程序打卡日历(整理了一下,看这个就好):https://blog.csdn.net/qq_43379916/article/details/124694248
下面这一篇就不删了,留做开发路上的一个回忆😀

实现后的效果图

关于点击签到:给每一天bind一个事件就好,下方例子中是根据默认数据生成的连续签到,默认数组中包含签到信息,就会高亮这一天,反之不高亮

未打卡状态
在这里插入图片描述
打卡状态
在这里插入图片描述
连续打卡状态
在这里插入图片描述
拿三张效果图进行对比,用户如已打卡当天的日期背景颜色则会显示为蓝色
累计打卡取已打卡数组长度就好
连续打卡则取数组中的第二位与第一位进行对比,如时间未超过24小时,则记一次打卡,以此类推

完整代码

wxml
<!-- 打卡日历页面 -->
<view class="continuouspunching_style">


  <!--累计打卡次数-->
  <view class="clockfrequency_view_style">
    <view class="daka_info">
      <view class="daka_tiansu">
        <text class="daka_number_style">{{count}}</text></view>
      <view class="daka_jiesao">累计打卡</view>
    </view>
    <view class="daka_info">
      <view class="daka_tiansu">
        <text class="daka_number_style">{{continuous_daka_count}}</text></view>
      <view class="daka_jiesao">连续打卡</view>
    </view>
  </view>
  <!--累计打卡次数end-->



  <!--日历-->
  <view class='all'>
    <view class="bar">

      <!-- 显示年月 -->
      <view class="date">
        <view class="sanjiao" bindtap="handleCalendar" data-handle="prev"></view>{{cur_year || "--"}} 年 {{cur_month || "--"}} 月
        <view class="you_sanjiao" bindtap="handleCalendar" data-handle="next"></view>
      </view>

    </view>
    <!-- 显示星期 -->
    <view class="week">
      <view wx:for="{{weeks_ch}}" wx:key="{{index}}" data-idx="{{index}}">{{item}}</view>
    </view>

    <view class='days'>
      <!-- 列 -->
      <view class="columns" wx:for="{{days.length/7}}" wx:for-index="i" wx:key="i">
        <view wx:for="{{days}}" wx:for-index="j" wx:key="j">
          <!-- 行 -->
          <view class="rows" wx:if="{{j/7 == i}}">
            <view class="rows" wx:for="{{7}}" wx:for-index="k" wx:key="k">
              <!-- 每个月份的空的单元格 -->
              <view class='cell' wx:if="{{days[j+k].date == null}}">
                <text decode="{{true}}">&nbsp;&nbsp;</text>
              </view>
              <!-- 每个月份的有数字的单元格 -->
              <view class='cell' wx:else>
                <!-- 当前日期已签到 -->
                <view wx:if="{{days[j+k].isSign == true}}" style='background-color:#2681FF;  color: white;' class='cell'>
                  <text>{{days[j+k].date}}</text>
                </view>
                <!-- 当前日期未签到 -->
                <view wx:else>
                  <text>{{days[j+k].date}}</text>
                </view>
              </view>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
  <!--日历end-->


  <!--打卡来历-->


  <view class="introduce">
    <view class="introduce-top">
      <view class="introduce-top-left">
        <view style="display: flex;flex-direction: row;">
          <text style="font-size: 33rpx;font-weight: 900;">班级签到打卡</text>
          <view class="introduceClock">
            <text>第一天打卡</text>
          </view>
        </view>
        <view>
          <text class="thefont">签到打卡时间:</text>
          <text class="thefont" style="color:#4875d8;">8月10日-9月10日</text>
        </view>
        <view>
          <text class="thefont">参与人数:100人次</text>
        </view>
      </view>

      <view class="introduce-top-right">
        <image class="top-right" src="../images/backImage.png"></image>
      </view>
    </view>
    <view style="border-top: 2rpx dashed #cdcdcd; margin-top:30rpx ;"></view>
    <view class="introduce-bottom">
      <text style="font-size: 33rpx;font-weight: 700;">!您有2个主题未打卡</text>
      <text style="font-size: 33rpx;font-weight: 700;color:#4875d8;">点击查看</text>
    </view>
  </view>
  <!--打卡来历end-->

</view>
wxss
/* pages/Calendar/Calendar.wxss */
/* 打卡日历 */
page{
  background-color: #F4F4F4;
   
}
.all{
  width: 92%;
  box-shadow:0 5px 8px -1px rgba(175, 171, 171, 0.2);
  padding-top: 20rpx;
  border-radius: 20rpx;
  position: absolute;
  top: 225rpx;
  left: 30rpx;
  background-color: white;
}

.all .bar{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding: 10rpx;
}

.all .bar image{
  width: 50rpx;
  height: 50rpx;
}

.all .week{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding: 20rpx;
  padding-left: 40rpx;
  padding-right: 40rpx;
  border-radius: 10px;
  color: #2681FF;
  margin: 20rpx;
  font-size: 30rpx;
}

.all .days{
  margin: 20rpx;
  padding: 10rpx;
  border-radius: 10px;
  font-size: 30rpx;
}

.all .columns{
  display: flex;
  flex-direction: column;
  justify-content: space-between; 
}

.all .columns .rows{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
}

.all .columns .rows .cell{
  width: 84rpx;
  height: 88rpx;
  margin: 3rpx;
  text-align: center;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.count .daynumber{
  display: flex;
  flex-direction: row;
  justify-content: center;
}

.count .daynumber .day{
  margin-top: 50rpx;
}















.continuouspunching_style{
  background-image: url('https://i.loli.net/2019/10/18/C9cPfSnrMUmqxz8.png');
   width: 100%;
   background-size: 100% auto;
   margin-top: -130rpx;
}
.continuouspunching_style::before{
  content: "";
  display: block;
  padding-top: 100%;
}


.clockfrequency_view_style{
  width: 77%;
  display: flex;
  justify-content: space-between;
  align-items: center;
  text-align: center;
  position: absolute;
  top: 62rpx;
  left: 95rpx;
}


.daka_info{
   color: white;
   line-height: 65rpx;
   letter-spacing: 5rpx;
}

.daka_jiesao{
  opacity: 0.8;
  font-size: 30rpx;
}
.daka_number_style{
   font-size: 60rpx;
}



.date{
  display: flex;
  justify-content: flex-start;
  align-items: center;
  font-size: 38rpx;
  font-weight: 500;
  color:rgba(51,51,51,1);
  margin: 0px auto;
}
.sanjiao{
  width: 0;
  height: 0;
  border-top: 9px solid transparent;
  border-right:  12px solid #2681FF;
  border-bottom:  9px solid transparent;
  margin-right: 20rpx;
}
.you_sanjiao{
  width: 0;
  height: 0;
  border-top: 9px solid transparent;
  border-left:  12px solid #ccc;
  border-bottom:  9px solid transparent;
  margin-left: 20rpx;
}




.introduce {
width: 90%;
margin: 0rpx auto;
padding-top: 20rpx;
background-color: white;
border-radius: 20rpx;
position: relative;
top: 347rpx;
box-shadow:0 5px 8px -1px rgba(175, 171, 171, 0.2);
margin-bottom: 100rpx;
}

.introduce-top {
width: 90%;
margin: 0rpx auto;
display: flex;
justify-content: space-between;
}

.introduceClock {
padding: 0rpx 10rpx;
height: 45rpx;
border-radius: 20rpx;
background-color: #4875d8;
color: white;
font-size: 24rpx;
font-weight: 900;
text-align: center;
line-height: 45rpx;
margin-left: 10rpx;
}

.thefont {
font-size: 22rpx;
font-weight: 500;
color: #cdcdcd;
}


.top-right {
width: 135rpx;
height: 135rpx;
margin: 12.5rpx auto;
}

.introduce-bottom {
width: 90%;
margin: 0rpx auto;
line-height: 80rpx;
display: flex;
justify-content: space-between;
}
js
//打卡日历页面
// 注意:util.js 里面没有其它自定义方法,就是我们在初始化一个新小程序时,util.js里默认自带的方法
var util = require('../../utils/util.js');

Page({

  /**
   * 页面的初始数据
   */
  data: {
    days: [], //存放一个月的天数数组
    signUp: [], //用户判断当天是否已打卡  可废除下方模拟打卡数组直接采用此数组

    //用于判断
    cur_year: 0, //年
    cur_month: 0, //月


    count: 0, //累计打卡的数量
    continuous_daka_count: 0, //连续打卡次数



    //monthArr: [],

    //模拟打卡状态的数组
    dakaArr: ['2019/09/1 10:33:34', '2019/09/5 10:33:34', '2019/10/1 10:33:34', '2019/10/5 10:33:34', '2019/10/7 10:33:34', '2019/10/8 10:33:34', '2019/10/9 10:33:34', '2019/10/10 10:33:34', '2019/10/11 10:33:34', '2019/10/13 10:33:34', '2019/10/14 10:33:34', '2019/10/15 10:33:34', '2019/10/16 10:33:34', '2019/10/17 10:33:34', '2019/10/18 10:33:34', '2019/10/19 10:33:34'],

  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function(options) {
    //获取当前年月  
    const date = new Date();
    var _cur_year = date.getFullYear();
    var _cur_month = date.getMonth() + 1;
    var _weeks_ch = ['日', '一', '二', '三', '四', '五', '六'];


    this.setData({
      cur_year: _cur_year,
      cur_month: _cur_month,
      weeks_ch: _weeks_ch,
    })
    this.calculateEmptyGrids(this.data.cur_year, this.data.cur_month); // 计算当月1号前空了几个格子,把它填充在days数组的前面
    this.calculateDays(this.data.cur_year, this.data.cur_month); // 绘制当月天数占的格子,并把它放到days数组中
    //获取当前用户当前任务的人签到状态
    this.onGetSignUp();
    console.log("年==》" + this.data.cur_year + "月===》" + this.data.cur_month);
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function() {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function() {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function() {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function() {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function() {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function() {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function() {

  },
  // 获取当月共多少天
  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();
  },

  // 计算当月1号前空了几个格子,把它填充在days数组的前面
  calculateEmptyGrids: function(year, month) {
    var that = this;
    //计算每个月时要清零
    that.setData({
      days: [],
    });
    const firstDayOfWeek = this.getFirstDayOfWeek(year, month);
    if (firstDayOfWeek > 0) {
      for (let i = 0; i < firstDayOfWeek; i++) {
        var obj = {
          date: null,
          isSign: false
        }
        that.data.days.push(obj);
      }
      this.setData({
        days: that.data.days,
      });
      //清空
    } else {
      this.setData({
        days: []
      });
    }
  },
  // //用于显示打卡状态   只需加载一次
  // onShowsPunchStatus(_month) {
  //   var that = this;
  //   let _days = that.data.days;
  //   let _arr = that.data.monthArr;
  //   if (that.data.monthArr.length < 1) {
  //     _arr.push({
  //       month: _month,
  //       days: _days
  //     });
  //     that.setData({
  //       monthArr: _arr
  //     })
  //   } else {
  //     var _monthArr = that.data.monthArr;
  //     for (var i = 0; i < _monthArr.length; i++) {
  //       for (var j = 0; j < _days.length; j++) {
  //         if (_days[j].isSign && _monthArr[i].month != _month) {
  //           console.log("进来添加");
  //           _monthArr.push({
  //             month: _month,
  //             days: _days
  //           });
  //           that.setData({
  //             monthArr: _monthArr,
  //           })
  //         }
  //       }
  //     }
  //   }
   
  // },


  // 绘制当月天数占的格子,并把它放到days数组中
  calculateDays: function(year, month) {
    var that = this;
    const thisMonthDays = this.getThisMonthDays(year, month);
    for (let i = 1; i <= thisMonthDays; i++) {
      var obj = {
        date: i,
        isSign: false
      }
      that.data.days.push(obj);
    }
    this.setData({
      days: that.data.days
    });

  },

  //匹配判断当月与当月哪些日子签到打卡
  onJudgeSign() {
    var that = this;
    var signs = that.data.signUp;
    var daysArr = that.data.days;
    for (var i = 0; i < signs.length; i++) {
      var current = new Date(signs[i].replace(/-/g, "/"));
      var year = current.getFullYear();
      var month = current.getMonth() + 1;
      var day = current.getDate();
      day = parseInt(day);
      for (var j = 0; j < daysArr.length; j++) {
        //年月日相同并且已打卡
        if (year == that.data.cur_year && month == that.data.cur_month && daysArr[j].date == day) {
          daysArr[j].isSign = true;
        }
      }
    }
    that.setData({
      days: daysArr
    });
    
    that.onJudgeContinuousClock();
  },

  //判断连续打卡次数
  onJudgeContinuousClock() {
    var that = this;
    let _count = 0;
    for (var i = 0; i < that.data.dakaArr.length; i++) {
      //把时间转换为时间戳
      if (i != 0) {
        var newDate_ = Date.parse(that.data.dakaArr[i]); //当天
        var theOriginalTime_ = Date.parse(that.data.dakaArr[i - 1]); //前一天
        //计算天
        let _day = parseInt(newDate_ - theOriginalTime_) / (1000 * 60 * 60);
        // console.log("当天:" + that.data.dakaArr[i] + ",前一天:" + that.data.dakaArr[i - 1] + ",当天与前天比较相差时间=====>" + _day + ",累计打卡==>" +_count);
        if (_day <= 24) {
          _count += 1;
        } else {
          _count = 0;
        }
      }
    }
    if (_count != 0) {
      that.setData({
        continuous_daka_count: parseInt(_count + 1),
      })
    } else {
      that.setData({
        continuous_daka_count: 0,
      })
    }
  },

  // 切换控制年月,上一个月,下一个月
  handleCalendar: function(e) {
    var that = this;
    const handle = e.currentTarget.dataset.handle;
    const cur_year = that.data.cur_year;
    const cur_month = that.data.cur_month;

    if (handle === 'prev') {
      let newMonth = cur_month - 1;
      let newYear = cur_year;
      if (newMonth < 1) {
        newYear = cur_year - 1;
        newMonth = 12;
      }
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
      this.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.onGetSignUp();
    } else {

      let newMonth = cur_month + 1;
      let newYear = cur_year;
      if (newMonth > 12) {
        newYear = cur_year + 1;
        newMonth = 1;
      }
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
     
      this.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.onGetSignUp();
    }
  },

  //获取当前用户该任务的签到数组
  onGetSignUp: function() {
    var that = this;
    var _arr = [];
    that.data.dakaArr.map(item => {
      _arr.push(item);
    })
    that.setData({
      signUp: _arr,
      count: _arr.length
    });
    //获取后就判断签到情况
    that.onJudgeSign();
  }
})

生成日历的思路

  • 得到当前月有多少天
new Date(year, month, 0).getDate()
  • 得到当月第一天是星期几
new Date(Date.UTC(year, month - 1, date)).getDay()
  • 根据星期几生成每月一号之前的空格

比如:3月份有31天,一号是星期2,那么完整的数组长度为31+1(按照星期一到星期天摆列)

扩展

拿windows系统自带的日历举例,默认生成76的格子数,得到上月有多少天,然后递减,插入到数组的最前面,得到当月有多少天,直接放入数组,最后下个月格子处理最简单,从1开始递增,一直到沾满76的格子

  • 15
    点赞
  • 85
    收藏
    觉得还不错? 一键收藏
  • 16
    评论
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值