微信小程序实现打卡日历功能


Posted in Javascript onSeptember 21, 2020

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

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

先展示一下成果:

微信小程序实现打卡日历功能

微信小程序实现打卡日历功能

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

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}}">  </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) {
  }
 }); 
 }
})

Calendar.json json文件

这里仅仅是改变了导航栏上的标题文字

{
 "navigationBarTitleText": "打卡日历"
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
基于jquery的仿百度搜索框效果代码
Apr 11 Javascript
jquery form表单序列化为对象的示例代码
Mar 05 Javascript
javascript中数组array及string的方法总结
Nov 28 Javascript
纯javascript模仿微信打飞机小游戏
Aug 20 Javascript
理解js对象继承的N种模式
Jan 25 Javascript
javascript时间戳和日期字符串相互转换代码(超简单)
Jun 22 Javascript
AngularJs定制样式插入到ueditor中的问题小结
Aug 01 Javascript
简单实现jQuery弹幕效果
May 06 jQuery
Express + Session 实现登录验证功能
Sep 08 Javascript
jQuery轮播图实例详解
Aug 15 jQuery
js 计数排序的实现示例(升级版)
Jan 12 Javascript
vue修饰符.capture和.self的区别
Apr 22 Vue.js
微信小程序实现时间预约功能
Nov 27 #Javascript
微信小程序使用component自定义toast弹窗效果
Nov 27 #Javascript
微信小程序自定义底部导航带跳转功能
Nov 27 #Javascript
koa2使用ejs和nunjucks作为模板引擎的使用
Nov 27 #Javascript
jQuery点击页面其他部分隐藏下拉菜单功能
Nov 27 #jQuery
js replace替换字符串同时替换多个方法
Nov 27 #Javascript
Vue中用props给data赋初始值遇到的问题解决
Nov 27 #Javascript
You might like
一个用php实现的获取URL信息的类
2007/01/02 PHP
PHP和Mysqlweb应用开发核心技术-第1部分 Php基础-2 php语言介绍
2011/07/03 PHP
linux iconv方法的使用
2011/10/01 PHP
深入php var_dump()函数的详解
2013/06/05 PHP
Yii实现自动加载类地图的方法
2015/04/01 PHP
php简单统计在线人数的方法
2016/05/10 PHP
从javascript语言本身谈项目实战
2006/12/27 Javascript
纯js网页画板(Graphics)类简介及实现代码
2012/12/24 Javascript
js Math 对象的方法
2013/09/01 Javascript
javascript放大镜效果的简单实现
2013/12/09 Javascript
jQuery setTimeout传递字符串参数报错的解决方法
2014/06/09 Javascript
jquery判断浏览器后退时候弹出消息的方法
2014/08/11 Javascript
利用JQuery直接调用asp.net后台的简单方法
2016/10/27 Javascript
如何使用vuejs实现更好的Form validation?
2017/04/07 Javascript
详解如何去除vue项目中的#——History模式
2017/10/13 Javascript
分析JS中this引发的bug
2017/12/12 Javascript
基于vue.js中关于下拉框的值默认及绑定问题
2018/08/22 Javascript
React Native开发封装Toast与加载Loading组件示例
2018/09/08 Javascript
vue 表单验证按钮事件交由父组件触发的方法
2018/12/17 Javascript
js笔试题-接收get请求参数
2019/06/15 Javascript
微信小程序按钮点击动画效果的实现
2019/09/04 Javascript
tracking.js实现前端人脸识别功能
2020/04/16 Javascript
分享8个JavaScript库可更好地处理本地存储
2020/10/12 Javascript
java直接调用python脚本的例子
2014/02/16 Python
对Python中数组的几种使用方法总结
2018/06/28 Python
Python3开发环境搭建详细教程
2020/06/18 Python
python不同系统中打开方法
2020/06/23 Python
css3的图形3d翻转效果应用示例
2014/04/08 HTML / CSS
西班牙语在线票务市场:SuperBoletería
2019/06/10 全球购物
REISS美国官网:伦敦最受欢迎的时尚品牌
2019/08/16 全球购物
TCP/IP中的TCP和IP分别承担什么责任
2012/04/21 面试题
What's the difference between Debug and Trace class? (Debug类与Trace类有什么区别)
2013/09/10 面试题
竞职演讲稿范文
2014/01/11 职场文书
食品安全责任书
2014/04/15 职场文书
2015年政务公开工作总结
2015/05/19 职场文书
Java 获取Word中所有的插入和删除修订的方法
2022/04/06 Java/Android