vue实现每日签到日历
实现思路
使用Vue实现每日签到日历需要结合日期处理、状态管理和UI渲染。核心逻辑包括生成当月日历数据、标记签到状态、处理签到交互。
日历数据生成
创建计算属性生成当月日历数组,包含上月残留天数、当月天数及下月补充天数:
computed: {
calendarDays() {
const year = this.currentDate.getFullYear();
const month = this.currentDate.getMonth();
// 当月第一天星期几(0-6)
const firstDay = new Date(year, month, 1).getDay();
// 当月总天数
const totalDays = new Date(year, month + 1, 0).getDate();
const days = [];
// 上月残留天数
const prevMonthDays = new Date(year, month, 0).getDate();
for (let i = firstDay - 1; i >= 0; i--) {
days.push({
date: prevMonthDays - i,
currentMonth: false,
signed: false
});
}
// 当月天数
for (let i = 1; i <= totalDays; i++) {
days.push({
date: i,
currentMonth: true,
signed: this.signedDates.includes(`${year}-${month + 1}-${i}`)
});
}
// 补充下月天数
const remaining = 42 - days.length;
for (let i = 1; i <= remaining; i++) {
days.push({
date: i,
currentMonth: false,
signed: false
});
}
return days;
}
}
签到状态管理
使用数组存储已签到日期,格式化为YYYY-M-D字符串:
data() {
return {
signedDates: [],
currentDate: new Date()
}
},
methods: {
signIn() {
const today = new Date();
const dateStr = `${today.getFullYear()}-${today.getMonth() + 1}-${today.getDate()}`;
if (!this.signedDates.includes(dateStr)) {
this.signedDates.push(dateStr);
}
}
}
日历UI渲染
使用CSS Grid布局7x6的日历表格:
<template>
<div class="calendar">
<div class="header">
<button @click="prevMonth">上一月</button>
<h3>{{ monthTitle }}</h3>
<button @click="nextMonth">下一月</button>
</div>
<div class="weekdays">
<div v-for="day in ['日','一','二','三','四','五','六']" :key="day">{{ day }}</div>
</div>
<div class="days">
<div
v-for="(day, index) in calendarDays"
:key="index"
:class="{
'other-month': !day.currentMonth,
'signed': day.signed,
'today': isToday(day)
}"
@click="handleDayClick(day)"
>
{{ day.date }}
<span v-if="day.signed" class="sign-mark">✓</span>
</div>
</div>
</div>
</template>
样式设计
基础日历样式示例:
.calendar {
width: 350px;
font-family: Arial;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.weekdays, .days {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
.weekdays div {
padding: 10px;
text-align: center;
font-weight: bold;
}
.days div {
padding: 10px;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
position: relative;
cursor: pointer;
}
.days div.other-month {
color: #ccc;
}
.days div.signed {
background-color: #e8f5e9;
}
.days div.today {
border: 1px solid #2196F3;
}
.sign-mark {
position: absolute;
bottom: 2px;
right: 2px;
color: #4CAF50;
font-size: 12px;
}
完整功能扩展
- 连续签到统计:增加计算属性统计连续签到天数
- 签到奖励:根据连续签到天数显示不同奖励
- 数据持久化:使用localStorage存储签到记录
- 动画效果:签到时添加CSS动画增强交互体验
// 连续签到计算示例
computed: {
consecutiveDays() {
// 实现连续签到逻辑
let count = 0;
const today = new Date();
for (let i = 0; i <= 6; i++) {
const date = new Date(today);
date.setDate(date.getDate() - i);
const dateStr = `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`;
if (this.signedDates.includes(dateStr)) {
count++;
} else {
break;
}
}
return count;
}
}






