我的项目要用到一个日历, 然而 css 和性能比拟奇怪, 就须要本人撸一个了
原理
一个日历以后月页面会显示 3 局部的日期天数
上月的,本月的,下月的
计算到这 3 局部组合起来的数组就是残缺的当月日历
所以重点在于计算这三局部就实现了
1. 上月的 new Date('2021-09-01').getDay()
2021 年 9 月 1 号是星期 3, 这时候就失去上月的 3 天
2. 本月的new Date(year, month, 0).getDate()
3. 下月的7 - (preAndCenter.length % 7)
最初失去当前页所以日期数组后就能够随便扩大本人要的性能了
<template>
<div class="calendar_mod">
<div class="header_warp">
<div class="header_btn" @click="monthSwitch('prev')"> 上 </div>
<div class="header_center">{{headerData.year}} / {{headerData.month}}</div>
<div class="header_btn" @click="monthSwitch('next')"> 下 </div>
</div>
<div class="week_warp">
<div class="week_item" v-for='(item,index) in weeks' :key='index'>{{item}}</div>
</div>
<div class="cell_warp">
<div class="cell_box" v-for='(item,index) in allDays' :key='index'>
<div :class="compDayClass(item)" >{{item.num}}</div>
</div>
</div>
</div>
</template>
<script>
export default {
name: "my-calendar",
props:{
marks:{
type:Array,
default:()=>{return []
}
}
},
data() {
return {headerData: {},
weeks: ["日", "一", "二", "三", "四", "五", "六"],
allDays: [],
preMonthDay: [], // 上月 day 数组};
},
created() {this.headerData = this.getCurrentDate(); // 获取以后年月
this.allDays = this.computer(this.headerData.year,this.headerData.month)
this.$watch(()=>{this.getMark(this.marks,this.headerData.year,this.headerData.month)
})
},
computed:{compDayClass(){return function(item){return `${item.type} ${item.mark?'marking':''}`
}
},
},
methods: {
// 计算方法汇总
computer(year,month){let cMonthWeek1 = this.getWeekInMonth( year,month);
let {preMonthNum ,cMonthNum} = this.getCurrentMonth(year,month);
let preMonthDays = this.compedNextTr1(preMonthNum, cMonthWeek1); // 获取当前页上月 arr
return this.getAllDay(preMonthDays,cMonthNum,this.compDay)
},
// 获取头部以后年月
getCurrentDate() {let currentDate = new Date();
let year = currentDate.getFullYear();
let month = currentDate.getMonth() + 1;
return {year, month};
},
// 获取当月数据
getCurrentMonth(year, month) {
// 获取月有多少天
let cMonthNum = new Date(year, month, 0).getDate();
let preMonthNum = new Date(year, month - 1, 0).getDate();
let nextMonthNum = new Date(year, month + 1, 0).getDate();
return {cMonthNum, preMonthNum, nextMonthNum};
},
// 计算某一月 1 号是星期几
getWeekInMonth(year, month) {return new Date(year + "/" + month + "/" + "01").getDay();},
// 计算第一行 当月显示的日期
compedNextTr1(preMonthNum, cMonthWeek1) {var pre = [],
temp = cMonthWeek1;
for (var i = 0; i < cMonthWeek1; i++) {pre.push(preMonthNum - temp + 1);
temp--;
}
return pre.map(item =>{return { num:item,type:'prev'}
})
},
// 组成当月日期的数组
compDay(cMonthNum,typer) {var cDay = Array.from({ length: cMonthNum}, (v, k) =>{return k + 1;});
return cDay.map(item =>{return { num:item,type: typer=='next'?'next':'current'}
})
},
// 获取所有的
getAllDay(preMonthDays,cMonthNum,compDay) {var preAndCenter = preMonthDays.concat(compDay(cMonthNum));
var lastDayNum = 7 - (preAndCenter.length % 7);
var allDays = preAndCenter.concat(compDay(lastDayNum,'next'));
return allDays
},
monthSwitch(type){let { year,month} = this.headerData
if(type == 'prev'){if(month == 1){
this.headerData.month =12
this.headerData.year = year - 1
this.allDays = this.computer(this.headerData.year,this.headerData.month)
}else{
this.headerData.month = this.headerData.month -1
this.allDays = this.computer(year,month-1)
}
}
if(type == 'next'){if(month == 12){
this.headerData.month =1
this.headerData.year = year + 1
this.allDays = this.computer(this.headerData.year,this.headerData.month)
}else{
this.headerData.month = this.headerData.month +1
this.allDays = this.computer(year,month+1)
}
}
},
// 依据传入的日期标记
getMark(marks,currentYear,currentMonth){
const dayMarks = marks.filter(item=>{let zday = (new Date(item))
if(zday.getMonth()+1 == currentMonth && zday.getFullYear() == currentYear){return zday.getDate()
}
})
const matchDays = dayMarks.map(item => (new Date(item)).getDate())
this.allDays.forEach(item =>{ delete item.mark})
this.allDays.forEach(item=>{
matchDays.forEach(item2=>{if(item.num == item2){item.mark = true}
})
})
this.$forceUpdate()},
},
};
</script>
<style scoped>
.calendar_mod {
border: 1px solid #333;
user-select: none;
}
.header_warp,
.week_warp,
.cell_warp {display: flex;}
.header_warp {
height: 50px;
border: 1px solid rgb(143, 53, 53);
justify-content: space-between;
}
.header_btn{
width: 100px;
text-align: center;
background-color: #999;
cursor: pointer;
}
.week_item {
flex: 1;
text-align: center;
border: 1px solid rgb(94, 179, 119);
}
.cell_warp {flex-wrap: wrap;}
.cell_box {
height: 70px;
flex: 0 0 14.285%;
margin: 5px 0;
}
.cell_box div{
width: 50px;
height: 100%;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
}
.cell_box .prev{background-color: #f1b9b9;}
.cell_box .next{background-color: #b9f1c1;}
.marking{color:red;}
</style>