在工作任务进行时,有一个签到日历的功能需求要实现,经过文档查询和样式优化实现了需求,在此记录一下。
技术背景:vue2+vant(样式控件)+ less + 一个公共样式文件
html实现部分:
<div class="calenderBox re_margin_top_16 re_sizing">
<!-- 切换月份 -->
<div class="re_width100 re_flex_between">
<div class="left">
<van-icon @click="dateOperate('down')" class="icon" name="arrow-left" size="16" />
</div>
<div class="re_font_14">{{ date[0] }}年{{ date[1] }}月</div>
<div class="right">
<van-icon @click="dateOperate('up')" class="icon" name="arrow" size="16" />
</div>
</div>
<!-- 日期列表 -->
<div class="date-list re_width100 re_margin_top_16">
<div class="date-content">
<!-- 日历头 -->
<div class="re_font_10 re_color_light re_flex_center" v-for="item in header" :key="item">
{{ item }}
</div>
<!-- 日列表 -->
<div class="re_margin_top_8 showday re_text_c re_sizing " v-for="(s, k) in dayList" :key="s + '-' + k">
<template v-if="s.month == date[1]">
<div v-if="s.signInStatus == 1" class="re_flex_center everyDay">
<img class="star" src="../../../assets/task/gray.png" alt="">
</div>
<!-- 补签 -->
<div @click="signIn(s, 2)" class="bu" v-else-if="s.signInStatus == 4">
<img class="bu" src="../../../assets/task/no.png" alt="">
</div>
<!-- -->
<div class="bu" v-else-if="s.signInStatus == 2">
<img class="bu" src="../../../assets/task/checkIn.png" alt="">
</div>
<!-- 签到 -->
<div @click="signIn(s, 1)" v-else-if="s.signInStatus == 0 && getDayText(s) == '今天'" class="bu re_sizing jintian re_sizing">
<img class="star" src="../../../assets/task/star.png" alt="">
<span class="re_color_calendar_color">+{{ s.getMoney }}</span>
</div>
<div v-else-if="s.signInStatus == 0 && getDayText(s) != '今天'" class="bu future re_sizing">
<img class="star" src="../../../assets/task/star.png" alt="">
<span class="color_redlight re_font_14">+{{ s.getMoney }}</span>
</div>
<div v-else class="re_flex_center everyDay">
<img class="star" src="../../../assets/task/gray.png" alt="">
</div>
<span :class="[
're_font_10',
s.month !== date[1] ? 'other-day' : '',
s.day === date[2] && s.month === date[1] ? getDayText(s) === '今天' ? 're_color_calendar_color' : 'today' : '',
]">
{{ getDayText(s) }}
</span>
</template>
</div>
</div>
</div>
</div>
js实现部分
export default {
name: "calendar",
data() {
return {
// 日历头
header: ["周日", "周一", "周二", "周三", "周四", "周五", "周六"],
// 选择日期
date: [],
// 天列表
dayList: [],
// 定时器
timer: null,
// 第一天是周几
weeks: 0,
userInfo: {},
setInfo: {},
successTitle:'签到成功',
handleSignInfo:{}
};
},
created() { },
mounted() {
let time = new Date();
this.date.push(
time.getFullYear(),
this.formatTime(time.getMonth() + 1),
this.formatTime(time.getDate())
);
this.countDay();
this.getSignInCalendar();
this.getInfo();
},
methods: {
getInfo(){
getSetInfo().then(res => {
this.setInfo = res.data;
})
},
goBack(){
this.$router.go(-1);
},
// beforeSignIn
beforeSignIn(){
extraSignIn({
signInDay: this.setInfo.signInDay
}).then(res => {
if(res.code == 1){
this.successVisible = true;
this.successTitle = '补签成功';
this.handleSignInfo = res.data;
this.getSignInCalendar();
setTimeout(() => {
this.successVisible = false;
}, 5000);
this.coinsVisible = false
}
if (res.code == 500) {
showDialog({ title: '提示', message: res.msg });
}
})
},
// 签到
signIn(s, type){
if(type == 2){
this.coinsVisible = true
this.setInfo.signInDay = s.signInDay
return
}
addSignIn({
signInDay: s.signInDay
}).then(res => {
if(res.code == 1){
this.successVisible = true;
this.successTitle = '签到成功';
this.handleSignInfo = res.data;
this.getSignInCalendar();
setTimeout(() => {
this.successVisible = false;
}, 5000);
}
if (res.code == 500) {
showDialog({ title: '提示', message: res.msg });
}
})
},
getSignInCalendar(){
signInCalendar({
signInDay: this.date.join('-')
}).then(res => {
this.dayList.forEach(item => {
res.data.forEach(item2 => {
if(item.signInDay === item2.signInDay){
item.getMoney = item2.getMoney;
item.signInStatus = item2.signInStatus;
}
})
})
})
getSignInInfo().then(res => {
this.userInfo = res.data;
})
},
formatTime(time) {
return time < 10 ? `0${time}` : time;
},
// 计算显示的天数据
countDay() {
let [y, m, d] = this.date;
// 获取第一天是周几
let week = new Date(`${y}/${m}/1`).getDay(),
// 获取当前月的上个月多少天
lastDays = this.getDays(y, m - 1),
// 获取这个月有多少天
days = this.getDays(y, m);
// 计算这个月有多少周
this.weeks = Math.ceil((days - (7 - week)) / 7) + 1;
// 将当前月份的天数生成数组
this.dayList = Array.from({ length: this.getDays(y, m) }, (v, k) => {
return {
day: this.formatTime(k + 1),
month: m,
year: y,
signInDay: `${y}-${m}-${this.formatTime(k + 1)}`
};
});
// 将本月1日前的数据补齐
for (let i = lastDays; i > lastDays - week; i--) {
this.dayList.unshift({
day: i,
// 如果当前日期是1月补齐的是去年12月的数据
month: +m - 1 === 0 ? 12 : this.formatTime(+m - 1),
year: +m - 1 === 0 ? y - 1 : y,
});
}
// 计算需要补齐多少天
let length = this.weeks * 7 - this.dayList.length;
// 将本月最后一天的数据补齐
for (let i = 1; i <= length; i++) {
this.dayList.push({
day: i,
// 如果当前日期是12月补齐的是明年年1月的数据
month: +m + 1 > 12 ? 1 : this.formatTime(+m + 1),
year: +m + 1 > 12 ? y + 1 : y,
});
}
},
// 校验选择的月份和已选择的日期是否匹配
checkDay() {
// 获取选择的年月有多少天 防止这年不是闰年 就将日期跳转到28号,或者有的月份没有31号就跳到30号
let num = this.getDays(this.date[0], this.date[1]);
if (num < this.date[2]) {
this.date.splice(2, 1, num);
}
},
// 获取某个月有多少天
getDays(year, month) {
// 一年中每个月的天数
let days = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
// 判断是不是闰年 2月29天
if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
days[1] = 29;
}
return days[month - 1];
},
//左右按钮点击事件
dateOperate(type) {
let [y, m, d] = this.date;
// 如果是向后翻
if (type === "up") {
// 日期向后翻 切换月份
if (+m === 12) {
this.date.splice(0, 1, y + 1);
this.date.splice(1, 1, "01");
} else {
this.date.splice(1, 1, this.formatTime(+m + 1));
}
// 如果是前后翻
} else {
if (+m === 1) {
this.date.splice(0, 1, y - 1);
this.date.splice(1, 1, 12);
} else {
this.date.splice(1, 1, this.formatTime(+m - 1));
}
}
this.countDay();
this.checkDay();
this.getSignInCalendar()
},
// 取消事件
cancel() {
this.$emit("cancel");
},
// 获取日期显示文本
getDayText(dateObj) {
const today = new Date();
const todayYear = today.getFullYear();
const todayMonth = this.formatTime(today.getMonth() + 1);
const todayDay = this.formatTime(today.getDate());
// 检查是否是今天
if (dateObj.year == todayYear && dateObj.month == todayMonth && dateObj.day == todayDay) {
return "今天";
}
// 检查是否是明天
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
const tomorrowYear = tomorrow.getFullYear();
const tomorrowMonth = this.formatTime(tomorrow.getMonth() + 1);
const tomorrowDay = this.formatTime(tomorrow.getDate());
if (dateObj.year == tomorrowYear && dateObj.month == tomorrowMonth && dateObj.day == tomorrowDay) {
return "明天";
}
// 其他日期显示月.日格式
return `${dateObj.month}.${dateObj.day}`;
},
}
}
css实现部分:
<style lang="less" scoped>
.calendar {
width: 100%;
min-height: 100vh;
background: url('../../../assets/task/calenderBg.png') no-repeat center top;
background-size: 100% 812px;
padding: 0 16px 16px;
background-color: #ffe9e9;
.title {
padding: 30px 0 18px 0;
width: 100%;
font-weight: 600;
.icon {
position: absolute;
left: 0px;
top: 33px;
}
.explain {
position: absolute;
right: 0px;
top: 34px;
}
}
.calenderBox {
width: 21.44rem;
min-height: 33.25rem;
background: #FFFFFF;
border: 0.06rem solid #FFFFFF;
border-radius: 1rem;
padding: 1rem;
}
.date-list {
padding-top: 0;
display: flex;
.date-content {
flex: 1;
height: 100%;
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr 1fr;
grid-template-rows: auto;
}
.showday{
margin: 8px auto 0;
}
.everyDay {
width: 2.5rem;
height: 3.38rem;
background: #F5F7F9;
border-radius: 6px;
}
.bu{
width: 2.5rem;
height: 3.38rem;
}
.color_redlight{
color: #FF455E;
}
.jintian{
border: 1px solid #FF455E;
border-radius: 6px;
padding-top: 6px;
}
.future{
background: #F5F7F9;
border-radius: 6px;
padding-top: 6px;
}
.star{
width: 18px;
height: 18px;
}
.other-day {
color: #CED1D9;
}
.today {
color: #394365;
}
}
}
</style>