小程序打卡日历

效果图:

在这里插入图片描述

写在前面

大家需要注意的是,因为我没有把这个当成一个组件来写,所以其中有些逻辑大家需要看着更改,
等有时间了,再把这个弄成一个小程序组件

js部分:

/*
生成日历思路:
1.得到指定月份有多少天
2.得到月份指定天是星期几(或者理解成每个月的1号是星期几)
*/

Page({
    data: {
        // 初始日期数组
        dateList: [],
        // 累计打卡
        accumulate: 0,
        // 连续打卡
        continuous: 0,
        // 日历天数
        days: [],
        date: {}
    },
    onLoad() {
        let date = this.getDate()
        this.setData({
            days: this.initCalendar(date),
            date
        })
    },
    /**
     * 初始化日历【核心方法】
     * @param {Date} date 日期参数
     */
    initCalendar(yearMonth) {
        let days = []; // 用于保存最后生成的日历
        // 得到参数 date 的1号是星期几
        let firstDayOfWeek = this.getDayOfWeek(yearMonth.year, yearMonth.month, 1)
        console.log(firstDayOfWeek);
        // 得到当前月的天数
        let toMonthDays = this.getMonthDays(yearMonth.year, yearMonth.month)

        // 处理上月的年月日 以及 格子数
        if (firstDayOfWeek > 0) {
            let y = yearMonth.year
            let m = yearMonth.month
            if (m == 1) {
                y -= 1
                m = 12
            } else {
                m--
            }

            let upMonthDays = this.getMonthDays(y, m) // 得到上个月的天数
            for (let i = 0; i < firstDayOfWeek; i++) {
                days.push({
                    ...this.createDayOption({
                        year: y,
                        month: m
                    }, upMonthDays--),
                    class: 'not-current-month'
                })
            }
            days.reverse()
        }

        // 处理当前月的格子数
        for (let i = 1; i <= toMonthDays; i++) {
            days.push(this.createDayOption(yearMonth, i))
        }

        // 处理下个月的年月以及格子数
        let d = 42 - days.length
        let ny = yearMonth.year
        let nm = yearMonth.month

        if (nm == 12) {
            ny += 1
            nm = 1
        } else {
            nm++
        }
        for (let i = 1; i <= d; i++) {
            days.push({
                ...this.createDayOption({
                    year: ny,
                    month: nm
                }, i),
                class: 'not-current-month'
            })
        }
        return days
    },
    // 切换日历
    handleSwitchCalendar(e) {
        let type = e.currentTarget.dataset.type;
        if (type == 'up') {
            if (this.data.date.month == 1) {
                let y = this.data.date.year
                this.setData({
                    ['date.month']: 12,
                    ['date.year']: y -= 1
                })
            } else {
                let m = this.data.date.month
                this.setData({
                    ['date.month']: m -= 1
                })
            }
        } else {
            if (this.data.date.month == 12) {
                let y = this.data.date.year
                this.setData({
                    ['date.month']: 1,
                    ['date.year']: y += 1
                })
            } else {
                let m = this.data.date.month
                this.setData({
                    ['date.month']: m += 1
                })
            }
        }
        this.setData({
            days: this.initCalendar(this.data.date),
        })
        this.updateDays()
    },
    // 处理打卡
    handlePunch(e) {
        let date = e.currentTarget.dataset.date
        console.log(date);
        let toDay = this.getDate()
        if (date.year <= toDay.year && date.month <= toDay.month) {
            if (date.active) return
            let arr = this.data.dateList
            arr.push(date)
            this.setData({
                dateList: arr
            })
            this.updateDays()
        } else {
            wx.showToast({
                icon: 'none',
                title: '日期超过了',
            })
        }
        this.handlePunchDays()
    },
    // 更新 days 状态
    updateDays() {
        let days = this.data.days
        days.forEach(n => {
            n.active = this.data.dateList.some(s => n.year == s.year && n.month == s.month && n.date == s.date)
        })
        this.setData({
            days
        })
    },
    // 处理累计打卡和连续打卡
    handlePunchDays() {
        // 累计打卡
        // 就是 dateList 的长度
        this.setData({
            accumulate: this.data.dateList.length
        })

        // 连续打卡
        let _count = 0;
        let arr = this.data.dateList
        // 再实际数据中,dateList 是不需要咱们手动排序的,我这边主要是用于测试,所以一些校验并未完善
        arr = arr.sort((a,b)=>{
            return Date.parse(`${a.year}/${a.month}/${a.date}`) - Date.parse(`${b.year}/${b.month}/${b.date}`)
        })
        console.log(arr);
        for (let i = 0; i < arr.length; i++) {
            //把时间转换为时间戳
            if (i != 0) {
                let newDate_ = Date.parse(`${arr[i].year}/${arr[i].month}/${arr[i].date}`); //当天
                let theOriginalTime_ = Date.parse(`${arr[i-1].year}/${arr[i-1].month}/${arr[i-1].date}`); //前一天
                //计算天
                let _day = parseInt(newDate_ - theOriginalTime_) / (1000 * 60 * 60);
                if (_day <= 24) {
                    _count += 1;
                } else {
                    _count = 0;
                }
            }
        }
        this.setData({
            continuous:_count != 0 ? _count + 1 : 0,
        })
    },
    // 1.得到指定月份有多少天
    getMonthDays(year, month) {
        return new Date(year, month, 0).getDate()
    },
    // 2.得到月份指定天是星期几
    getDayOfWeek(year, month, date) {
        // Date.UTC返回从1970的毫秒数
        return new Date(Date.UTC(year, month - 1, date)).getDay()
    },
    // 生成每一天日期参数
    createDayOption(ym, d) {
        return {
            year: ym.year,
            month: ym.month,
            date: d
        }
    },
    // 返回指定年月日
    getDate(time) {
        let caledar = time ? new Date(time) : new Date()
        let year = caledar.getFullYear()
        let month = caledar.getMonth() + 1
        let date = caledar.getDate()
        let h = caledar.getHours()
        let m = caledar.getMinutes()
        let s = caledar.getSeconds()
        let whichDay = caledar.getDay()
        return {
            year,
            month,
            date,
            h,
            m,
            s,
            whichDay
        }
    }
})

wxml:

<view class="container">
    <view class="header ui-flex-between">
        <view>
            <view><text class="count">{{ accumulate }}</text></view>
            <view>累计打卡</view>
        </view>
        <view>
            <view><text class="count">{{ continuous }}</text></view>
            <view>连续打卡</view>
        </view>
    </view>
    <!-- 日历卡片部分 S -->
    <view class="calendar">
        <view class="label ui-flex">
            <view class="triangle left" data-type="up" bindtap="handleSwitchCalendar"></view>
            <view>{{ date.year }}年{{ date.month }}月</view>
            <view class="triangle right" data-type="next" bindtap="handleSwitchCalendar"></view>
        </view>
        <!-- 绘制周一到周天的格子:默认 42 个 -->
        <view class="calendar-days ui-flex-wrap">
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view class="day-label"></view>
            <view wx:for="{{ days }}" wx:key="index" class="day {{item.class}} {{ item.active ? 'active-day' : '' }}" data-date="{{ item }}" bindtap="handlePunch">{{ item.date }}</view>
        </view>
    </view>
    <!-- 日历卡片部分 E -->
</view>

css:

page{
    height: 100%;
}
.ui-flex-between{
    display: flex;
    justify-content: space-between;
    align-items: center;
}
.ui-flex{
    display: flex;
    justify-content: flex-start;
    align-items: center;
}
.ui-flex-wrap{
    display: flex;
    flex-wrap: wrap;
}
.container{
    width: 100%;
    height: 100%;
    background-image: url('https://i.loli.net/2019/10/18/C9cPfSnrMUmqxz8.png');
    background-size: 100%;
}

.header,.calendar{
    width: 90%;
    margin: 0 auto;
}
.header{
    padding: 50rpx 70rpx;
    color: #fff;
    text-align: center;
    line-height: 60rpx;
    font-size: 30rpx;
    box-sizing: border-box;
}
.header .count{
    font-size: 50rpx;
    margin-right: 4rpx;
}
.calendar{
    background-color: #fff;
    border-radius: 30rpx;
    box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.3);
    font-size: 24rpx;
}

.label{
    justify-content: center;
    padding: 30rpx 0;
}
.triangle{
    border-left: 20rpx solid transparent;
    border-right: 20rpx solid transparent;
    border-bottom: 30rpx solid #2681ff;
}
.label > .left,.right{
    margin: 0 20rpx;
}
.label > .left{
    transform: rotate(-90deg);
}
.label > .right{
    transform: rotate(90deg);
}

/* 格子部分css */
.calendar-days > view{
    width: calc(100% / 7);
    text-align: center;
}
.calendar-days > .day{   
    padding: 30rpx 0;
    color: #444;
}
.not-current-month{
    color: #ccc !important;
}
.active-day{
    background-color: #2681ff;
    border-radius: 50%;
    color: #fff !important;
}

源码仓库:https://gitee.com/codeds/noob/tree/master/punch-calendar

  • 8
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

开发路上的AZhe

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值