先看一下实现的效果:
实现日历的逻辑:
- 先写出日历的大致结构,分两个部分,头部和主体部分,日历先显示6排7列,总共42个数字,按从1到42来显示:
<div class="every-day" v-for="item in 42" :key="item"></div>
像这样:
然后获取当前日期是星期几,用日历中的数字减去这个数字,就使得1号在正确的位置上显示了。
获取当前日期是星期几的方法:
new Date(this.year, this.month - 1, 1).getDay(); //获取当前日期是星期几
然后再判断经过计算的日期,如果小于等于0,则应显示上个月被排版到这个月的日期,如果大于0且大于当前月份的总天数的话,则是下个月被排版到这个月的日期,也就是日历上的灰体字。
上个月日期显示:当前item 减去这个月1号的星期数,再加上上个月的总天数
<div class="other-day" v-else-if="item - beginDay <= 0">
{{item - beginDay + prevDays}}
</div>
下个月日期显示:当前item 减去这个月1号的星期数,再减去当前月的总天数
<div class="other-day" v-else>{{item - beginDay - curDays}}</div>
写不动了,直接上带注释的代码吧…
全部代码!
<template>
<div class="calender">
<div class="dateHeader">
<div class="prev-month" @click="handlePrev"></div>
<div class="show-date">{{year}}年{{month}}月{{day}}日</div>
<div class="next-month" @click="handleNext"></div>
</div>
<div class="dateContent">
<div class="week-header">
<div v-for="item in ['日','一','二','三','四','五','六']" :key="item">
{{item}}
</div>
</div>
<div class="week-day">
<div class="every-day" v-for="item in 42" :key="item">
{{item}}
<div v-if="item - beginDay > 0 && item - beginDay <= curDays"
:class="{'now-day': `${year}-${month}-${item-beginDay}` === curDate,
'active-day': `${year}-${month}-${item-beginDay}` === `${year}-${month}-${day}`}"
:data-day="item - beginDay"
@click="handleChooseDay">
{{item - beginDay}}
</div>
<div class="other-day" v-else-if="item - beginDay <= 0">{{item - beginDay + prevDays}}</div>
<div class="other-day" v-else>{{item - beginDay - curDays}}</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data () {
return {
year: null,
month: null,
day: null,
curDate: ''
}
},
created(){
this.getInitTime();
// console.log(new Date(this.year, this.month - 1, 1).getDay());
},
methods: {
getInitTime () {
//初始化,获取当前年月日
const date = new Date();
this.year = date.getFullYear();
this.month = date.getMonth() + 1;
this.day = date.getDate();
this.curDate = `${this.year}-${this.month}-${this.day}`;
},
handleChooseDay(e){
//获取点击选中的日期 :data-day
console.log(e.target.dataset); // DOMStringMap {day: "11"}
this.day = e.target.dataset.day;
},
handlePrev(){
//点击上个月,如果是1月,则上个月是12月,年份减1
if(this.month == 1){
this.month = 12;
this.year -- ;
}else{
this.month --;
}
this.computedDay();
},
handleNext(){
//点击下个月 如果是12月,下个月则变成1月,年份加一
if(this.month == 12){
this.month = 1;
this.year ++;
}else{
this.month ++;
}
this.computedDay();
},
computedDay(){
//如果选中的是一个月里的最后一天,比如31,下一个月只有30天,反到下一个月要自动选中30
const allDay = new Date(this.year, this.month, 0).getDate();
if(this.day > allDay){
this.day = allDay;
}
}
},
computed: {
beginDay() {
//这个月的1号是星期几
return new Date(this.year, this.month - 1, 1).getDay();
},
curDays() {
//直接拿到这个月的天数
return new Date(this.year, this.month, 0).getDate();
},
prevDays(){
//上个月的天数
return new Date(this.year, this.month-1, 0).getDate();
}
}
}
</script>
<style>
.calender{
width: 560px;
/* height: 500px; */
}
.dateHeader {
margin-bottom: 10px;
}
.dateHeader div{
display: inline-block;
}
.prev-month{
width: 0;
height: 0;
border-width: 15px;
border-style: solid;
border-color:transparent #f44444 transparent transparent;
}
.show-date{
width: 87%;
text-align: center;
height: 30px;
line-height: 30px;
vertical-align: top;
}
.next-month{
width: 0;
height: 0;
border-width: 15px;
border-style: solid;
border-color:transparent transparent transparent #f44444;
}
.week-header{
background: #f44444;
}
.week-header div{
display: inline-block;
width: 70px;
height: 35px;
line-height: 35px;
text-align: center;
color: #fff;
margin-left: 5px;
margin-right: 5px;
}
.week-day div{
width:70px;
height: 45px;
line-height: 45px;
margin: 5px;
text-align: center;
display: inline-block;
cursor: pointer;
}
.other-day {
color: #999;
}
.now-day{
color: #fff;
background: #f44444;
}
.active-day{
border: 2px solid #f44444;
}
</style>
(完)