Vue實現(xiàn)萬年日歷的示例詳解
前言
又是一個老生常談的功能,接下來會從零實現(xiàn)一個萬年日歷,從布局到邏輯,再到隨處可見的打卡功能。涉及的內(nèi)容有:
- 日歷的布局
- 日期數(shù)據(jù)的產(chǎn)生
- 年月的變化
- 連續(xù)最長打卡日期
- 補卡邏輯

1.日歷的布局
<template>
<div class="calendar">
<!-- 年份和日期變化 -->
<div class="select">
<span class="select-icon select-sub" @click="changeYear(-1)">《</span>
<span class="select-icon select-sub select-month" @click="changeMonth(-1)"><</span>
<span>{{ currentMonth }}</span>
<span class="select-icon select-add select-month" @click="changeMonth(+1)">></span>
<span class="select-icon select-add" @click="changeYear(+1)">》</span>
</div>
<!-- 日歷標題 -->
<ul class="calendar-header">
<li v-for="(item, index) in headerData" :key="index" class="calendar-header-item">
<span>{{ item }}</span>
</li>
</ul>
<!-- 日期內(nèi)容 -->
<div class="calendar-box">
<div class="calendar-box-item" :class="{ delMark: !hasRemarkDays.includes(item) }" v-for="(item, index) in baseDateList" :key="index">
<!-- 最高層級顯示圓形日期 -->
<div class="item-wrap" :class="{ hasMarked: hasRemarkDays.includes(item) }" @click="toRemark(item, currentDate)">
<span class="item-date">{{ item ? item : "" }}</span>
<span class="item-patch" v-if="isShowPatch && !hasRemarkDays.includes(item) && item && item < currentDate">補卡</span>
<span class="item-current" v-if="currentDate == item"><i></i></span>
<span class="item-continue" v-if="continueMarkObj.maxDay == item">連續(xù){{ continueMarkObj.maxLen }}天</span>
</div>
<!-- 全遮罩背景淡橙色背景 -->
<span class="all-mark" v-if="hasRemarkDays.includes(item)"></span>
<!-- 左右遮罩,如果左邊無打卡,遮?。蝗绻疫厽o打卡,遮住 -->
<span class="left-mark" v-if="index % 7 === 0 || !hasRemarkDays.includes(item - 1)"></span>
<span class="right-mark" v-if="index % 7 === 6 || !hasRemarkDays.includes(item + 1)"></span>
</div>
</div>
</div>
</template>2.日期數(shù)據(jù)的產(chǎn)生
computed: {
// 返回當前的實際天數(shù),從周一算起
baseDateList() {
let date = new Date(this.currentMonth);
let monthFlag = date.getMonth() + 1;
let yearFlag = date.getFullYear();
let currentData = date.getDay();
let dayLength = new Date(yearFlag, monthFlag, 0).getDate();
// 周一之前的補0
let dateBaseData = [];
for (let i = 0; i < currentData; i++) {
dateBaseData.push(0);
}
// 周一之后的實際填寫
for (let i = 0; i < dayLength; i++) {
dateBaseData.push(i + 1);
}
return dateBaseData;
},
}其中currentData表示今天是周幾,在此之前的數(shù)組都補充為0,dayLength表示這月共多少天,然后,全部push進日期數(shù)據(jù)中。通過flex布局中的flex-wrap: wrap;讓其自動換行即可。
3.年月的變化
// 修改年:當type = +1時,表示加一年,為-1時反之
changeYear(type) {
let time = new Date(this.currentMonth);
let year = time.getFullYear() + type;
let month = time.getMonth() + 1;
this.currentMonth = `${year}-${month}`;
},
// 修改月:當type = -1時,表示加一月,為-1時次之
changeMonth(type) {
let time = new Date(this.currentMonth);
let year = time.getFullYear();
let month = time.getMonth() + 1;
if (month === 12 && type > 0) { // 12月,并且是加的情況,年加1,月變?yōu)?
year++
month = 1
} else if(month === 1 && type < 0) { // 1月,并且是減的情況,年減1,月變?yōu)?2
year--
month = 12
} else { // 其他情況,直接變化變量type的大小
month += type
}
this.currentMonth = `${year}-${month}`;
},引入type,既是加減的標志位,又是變量的大小。
4.連續(xù)最長打卡日期
getMaxDay() {
let arr = this.hasRemarkDays;
let buffChild = [];
let max = [];
for (let i = 0; i < arr.length; i++) {
// 如果子集不連續(xù)了,重新進行賦值和更新
if (buffChild.length && arr[i] - buffChild[buffChild.length - 1] > 1) {
max = max.length > buffChild.length ? [...max] : [...buffChild];
buffChild = [];
buffChild.push(arr[i]);
continue;
}
// 如果不是,直接進行累計
buffChild.push(arr[i]);
}
return max.length > buffChild.length ? [...max] : [...buffChild];
},假設(shè)max是最大的數(shù)組,那么,每次找到連續(xù)的數(shù)組都max進行對比并更新。在節(jié)點中,通過:class="{ hasMarked: hasRemarkDays.includes(item) }"的方式,為其添加hasMarked的樣式。
5.補卡日期
補卡邏輯很簡單,當前日期之前的日期,均可進行補卡,然后,在觸發(fā)的方法中,通過$emit的方式向父組件傳遞需要補卡的日期,并觸發(fā)補卡邏輯。
總結(jié):日歷的實現(xiàn)主要是應用JavaScript中Date對象的api和經(jīng)典的flex布局,而最長連續(xù)打卡是常規(guī)算法最長連續(xù)子序列的實現(xiàn)方式之一。
到此這篇關(guān)于Vue實現(xiàn)萬年日歷的示例詳解的文章就介紹到這了,更多相關(guān)Vue萬年日歷內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Vite?vue3多頁面入口打包以及部署踩坑實戰(zhàn)
因為我們公司的項目是多頁面應用,不同于傳統(tǒng)單頁面應用,一個包就可以了,下面這篇文章主要給大家介紹了關(guān)于Vite?vue3多頁面入口打包以及部署踩坑的相關(guān)資料,需要的朋友可以參考下2022-05-05
關(guān)于elementUI select控件綁定多個值(對象)
這篇文章主要介紹了關(guān)于elementUI select控件綁定多個值(對象),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-04-04

