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


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 相关文章推荐
单击按钮显示隐藏子菜单经典案例
Jan 04 Javascript
javascript获取函数名称、函数参数、对象属性名称的代码实例
Apr 12 Javascript
jQuery函数map()和each()介绍及异同点分析
Nov 08 Javascript
网页禁用右键菜单和鼠标拖动选择方法小结
Feb 25 Javascript
JavaScript程序设计之JS调试
Dec 09 Javascript
CSS3 media queries结合jQuery实现响应式导航
Sep 30 Javascript
基于jQuery的checkbox全选问题分析
Nov 18 Javascript
微信小程序实战之轮播图(3)
Apr 17 Javascript
JS开发中基本数据类型具体有哪几种
Oct 19 Javascript
vue 中引用gojs绘制E-R图的方法示例
Aug 24 Javascript
node.js域名解析实现方法详解
Nov 05 Javascript
在Vue中使用Viser说明(基于AntV-G2可视化引擎)
Oct 28 Javascript
微信小程序实现时间预约功能
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实现域名whois查询的代码(数据源万网、新网)
2010/02/22 PHP
thinkPHP5框架分页样式类完整示例
2018/09/01 PHP
Linux下源码包安装Swoole及基本使用操作图文详解
2019/04/02 PHP
php实现通过stomp协议连接ActiveMQ操作示例
2020/02/23 PHP
关于Blog顶部的滚动导航条代码
2006/09/25 Javascript
IE6弹出“已终止操作”的解决办法
2010/11/27 Javascript
利用div+jquery自定义滚动条样式的2种方法
2013/07/18 Javascript
浅析基于WEB前端页面的页面内容搜索的实现思路
2014/06/10 Javascript
浅谈javascript中createElement事件
2014/12/05 Javascript
jquery实现带缩略图的可定制高度画廊效果(5种)
2015/08/28 Javascript
基于JavaScript实现移除(删除)数组中指定元素
2016/01/04 Javascript
深入浅析AngularJS中的module(模块)
2016/01/04 Javascript
手机浏览器 后退按钮强制刷新页面方法总结
2016/10/09 Javascript
Vue.js 2.0和Cordova开发webApp环境搭建方法
2018/02/26 Javascript
element-ui多文件上传的实现示例
2019/04/10 Javascript
vue excel上传预览和table内容下载到excel文件中
2019/12/10 Javascript
详解Vue中的Props与Data细微差别
2020/03/02 Javascript
零基础写python爬虫之神器正则表达式
2014/11/06 Python
Python守护进程用法实例分析
2015/06/04 Python
python flask安装和命令详解
2019/04/02 Python
Python获取时间范围内日期列表和周列表的函数
2019/08/05 Python
python Django框架实现web端分页呈现数据
2019/10/31 Python
解决Keras中Embedding层masking与Concatenate层不可调和的问题
2020/06/18 Python
如何使用 Flask 做一个评论系统
2020/11/27 Python
python绘制高斯曲线
2021/02/19 Python
Coach澳大利亚官方网站:美国著名时尚奢侈品牌
2017/05/24 全球购物
台湾网友喜爱的综合型网路购物商城:Yahoo! 奇摩购物中心
2018/03/10 全球购物
印尼最大的网上书店:Gramedia.com
2018/09/13 全球购物
工程造价与财务管理专业应届生求职信
2013/10/06 职场文书
我未来的职业规划范文
2014/01/11 职场文书
2014年客服工作总结范文
2014/11/13 职场文书
工程部主管岗位职责
2015/02/12 职场文书
少先队中队工作总结2015
2015/07/23 职场文书
反腐倡廉心得体会2016
2016/01/13 职场文书
简单了解 MySQL 中相关的锁
2021/05/25 MySQL
pytorch 梯度NAN异常值的解决方案
2021/06/05 Python