打卡小程序的实现思路

生活中有各种可以打卡的app,例如背单词打卡什么的,本人觉得很有意思,于是本人在大二时做了一款诚信状打卡的微信小程序,这里讲述一下编写的过程。

先说一下开发环境:用的是微信web开发工具开发的,后台采用了Bmob后台,比较方便。

先展示一下成果:
2018年6月的打卡情况,有几天偷懒了没打卡
2018年7月的打卡情况,17号活动结束,就没有打卡了

话不多说,直接上代码,里面也有挺多的注释,以防自己忘记,当然各位如果直接复制过去肯定不能有当前的效果,注意后台数据的交互,不过做一个界面还是没有问题的。

Calendar.wxml 页面文件
页面上显示出来的东西,布局上主要是一个年月栏、上一个月和下一个月的按钮;然后是星期栏,就是日一二三四五六,然后就是每个月的日期,注意每个月的前面可能有空的地方。这里面用wx:if标签来区分当前日期有无打卡的情况。

<!--pages/Calendar/Calendar.wxml-->
<!-- 打卡日历页面 -->
<view class='all'>
  <view class="bar">
    <!-- 上一个月 -->
    <view class="previous" bindtap="handleCalendar" data-handle="prev">
      <image src='../../images/pre.png'></image>
    </view>
    <!-- 显示年月 -->
    <view class="date">{
   
   {cur_year || "--"}} 年 {
   
   {cur_month || "--"}} 月</view>
    <!-- 下一个月 -->
    <view class="next" bindtap="handleCalendar" data-handle="next">
      <image src='../../images/next.png'></image>
    </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:#83C75D' 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 class='count'>
    <text>截至目前,你已坚持打卡</text>
    <view class='daynumber'>
    <text class='number'>{
   
   {count}}</text>
    <text class='day'>天</text>
    </view>    
    <text>请再接再厉,继续努力</text>
  </view>
</view>

Calendar.wxss 样式文件
这个就是让页面显示得更好看一点了,里面有些属性更改之后可能会导致整个页面的格式变得很乱,说明自己的功夫还是不到家。

/* pages/Calendar/Calendar.wxss */
/* 打卡日历 */
.all{
  margin-top: 20rpx;
}

.all .bar{
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  margin: 30rpx 20rpx;
  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;
  margin: 20rpx;
  border-radius: 10px;
  background-color: #acd;
}

.all .days{
  margin: 20rpx;
  padding: 10rpx;
  border-radius: 10px;
  background-color: #acd;

}

.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;
}

.count{
  margin: 20rpx;
  padding: 30rpx;
  display: flex;
  text-align: center;
  border-radius: 10px;
  flex-direction: column;
  justify-content: center;
  background-color: #acd;
  align-items: center;
}

.count .number{
  color: red;
  font-size: 60rpx;
  background-color: #fff;
  width: 100rpx;
  height: 100rpx;
  border-radius: 50%;
  display: flex;
  flex-direction: column;
  justify-content: center;
  margin: 20rpx;
}

.count text{
  margin: 10rpx;
}

Calendar.js JavaScript文件
js文件里面涉及到Bmob的操作,这里就不多说Bmob的操作了,感兴趣的同学可以去参考它的官方文档。
然后里面主要是对上一个月、下一个月的点击函数进行处理,以及对某年某月的每个日期进行初始化(尤其是每个月前的可能有的几个空格进行了处理),然后就是判断某个日期在后台数据中是否有打卡。

// pages/Calendar/Calendar.js
//打卡日历页面
var util = require('../../utils/util.js');
var Bmob = require('../../utils/bmob.js');
Page({

  /**
   * 页面的初始数据
   */
  data: {
    objectId:'',
    days:[],
    signUp:[],
    cur_year:0,
    cur_month:0,
    count:0
  },

  /**
   * 生命周期函数--监听页面加载
   */
  onLoad: function (options) {
    this.setData({objectId : options.objectId}); 
    //获取当前年月  
    const date = new Date();
    const cur_year = date.getFullYear();
    const cur_month = date.getMonth() + 1;
    const weeks_ch = ['日', '一', '二', '三', '四', '五', '六'];
    this.calculateEmptyGrids(cur_year, cur_month);
    this.calculateDays(cur_year, cur_month);
    //获取当前用户当前任务的签到状态
    this.onGetSignUp();
    this.setData({
      cur_year,
      cur_month,
      weeks_ch
    })
  
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  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: []
      });
    }
  },

  // 绘制当月天数占的格子,并把它放到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:function(){
    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].date.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 && signs[i].isSign == "今日已打卡"){
          daysArr[j].isSign = true;
        }
      }
    }
    that.setData({days:daysArr});
  },

  // 切换控制年月,上一个月,下一个月
  handleCalendar:function(e) {
    const handle = e.currentTarget.dataset.handle;
    const cur_year = this.data.cur_year;
    const cur_month = this.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.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.onGetSignUp();      
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
    } else {
      let newMonth = cur_month + 1;
      let newYear = cur_year;
      if (newMonth > 12) {
        newYear = cur_year + 1;
        newMonth = 1;
      }
      this.calculateEmptyGrids(newYear, newMonth);
      this.calculateDays(newYear, newMonth);
      this.onGetSignUp();      
      this.setData({
        cur_year: newYear,
        cur_month: newMonth
      })
    }
  },

  //获取当前用户该任务的签到数组
  onGetSignUp:function(){
    var that = this;
    var Task_User = Bmob.Object.extend("task_user");
    var q = new Bmob.Query(Task_User);
    q.get(that.data.objectId, {
      success: function (result) {
        that.setData({
          signUp : result.get("signUp"),
          count : result.get("score")
        });
        //获取后就判断签到情况
        that.onJudgeSign();
      },
      error: function (object, error) {
      }
    });   
  }
})

猜你喜欢

转载自blog.csdn.net/qq_28471389/article/details/110234522