参考文档: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}}"> </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的格子