效果图
先说一下大致思路:如下图,日历主要分为2个部分,最开始的部分可以使用dateObject.getDay()这个方法获取当月第一天是星期几,然后渲染出对应的空白部分,接着就可以直接获取当月的具体天数,直接渲染即可
直接上代码
<template>
<!-- 日历组件 -->
<div class="hello" @click="changeDate">
<div class="calendar-head" style="display: flex;width: 338px;padding: 10px 16px;justify-content: space-around">
<div class="calendar-year">
<div class="triangle-l" @click="skip('preYear', CurrentYear > 0)"></div>
<el-select
v-model="CurrentYear"
placeholder="请选择"
size="mini"
>
<el-option
v-for="item in yearList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<div class="triangle-r" @click="skip('nextYear', CurrentYear)"></div>
</div>
<div class="calendar-month">
<div class="triangle-l extend-ml-36" @click="skip('preMonth', CurrentMonth > 1)"></div>
<el-select
v-model="CurrentMonth"
placeholder="请选择月份"
size="mini"
>
<el-option
v-for="item in monthList"
:key="item.value"
:label="item.label"
:value="item.value"
>
</el-option>
</el-select>
<div class="triangle-r" @click="skip('nextMonth', CurrentMonth < 12)"></div>
</div>
</div>
<ul class="calendar calendar-content">
<li>日</li>
<li>一</li>
<li>二</li>
<li>三</li>
<li>四</li>
<li>五</li>
<li>六</li>
</ul>
<ul class="calendar calendar-detail-head" :class="{'changeHeight':changeHeight}">
<li
v-for="item in CurrentDay"
:key="item + 'a'"
></li>
<li
v-for="item in totalDay"
:key="item + 'b'"
>
{{ item }}
</li>
</ul>
</div>
</template>
<script>
const monthDays = [
31,
28,
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
]
export default {
data() {
return {
yearList: [
{ value: 2021, label: 2021 },
{ value: 2020, label: 2020 },
{ value: 2019, label: 2019 },
],
monthList: [
{ value: 1, label: 1 },
{ value: 2, label: 2 },
{ value: 3, label: 3 },
{ value: 4, label: 4 },
{ value: 5, label: 5 },
{ value: 6, label: 6 },
{ value: 7, label: 7 },
{ value: 8, label: 8 },
{ value: 9, label: 9 },
{ value: 10, label: 10 },
{ value: 11, label: 11 },
{ value: 12, label: 12 }
],
CurrentMonth: 1, //当前月份
CurrentYear: 2021, //当前年份
CurrentDay: 1, //以数字取得当月第一天对应的星期
totalDay: 31, //当月天数
changeHeight: false, //当日历行数改变时触发
dateFlag: null,
}
},
watch: {
/**
* 监听年份的改变
**/
CurrentYear() {
this.monthData()
},
/**
* 监听月份的改变
**/
CurrentMonth() {
this.monthData()
}
},
created() {
this.CurrentYear = new Date().getFullYear()
this.CurrentMonth = new Date().getMonth() + 1
this.monthData()
//切换日期对应的函数
this.dateFlag = {
'preYear': () => {
this.CurrentYear -= 1;
},
'preMonth': () => {
this.CurrentMonth -=1;
},
'nextMonth': () => {
this.CurrentMonth += 1;
},
'nextYear': () => {
this.CurrentYear +=1;
}
}
},
methods: {
/**
*获取日历当月数据
**/
monthData() {
this.getDay()
this.totalDay = this.countDays(
Number(this.CurrentYear),
Number(this.CurrentMonth)
)
//判断日期是否多了一行
this.changeHeight = this.CurrentDay + this.totalDay > 35
},
/**
*用于父组件,当点击日历组件里面的内容不关闭组件,反之,点击外面的内容关闭组件
**/
changeDate() {
this.$emit('clickDate', 'clickDate')
},
/**
*获取当月天数
**/
countDays(year, month) {
//定义月份的数组,函数运行可以直接返回一个数值.
if (2 === month) return (0 === year % 4 && 0 !== year % 100) || 0 === year % 400 ? 29 : 28
return monthDays[month - 1]
},
/**
*以数字取得当月第一天对应的星期
**/
getDay() {
this.CurrentDay = new Date(
this.CurrentYear + '-' + this.CurrentMonth
).getDay();
},
/**
*切换年月份
* @param flag 标识年月增减
* @param effective 是否有效
**/
skip(flag,effective = true) {
if(effective){
this.dateFlag[flag]()
}
}
}
}
</script>
<style scoped>
.hello {
background-color: white;
width: 370px;
height: 272px;
}
.calendar-year, .calendar-month{
display: flex;
}
.calendar {
width: 338px;
margin: 0 auto;
padding: 16px 0;
display: flex;
flex-wrap: wrap;
}
.calendar li {
width: 14.28%;
height: 38px;
text-align: center;
line-height: 35px;
list-style: none;
}
.calendar-content {
background-color: #f7f6f6;
padding: 0;
}
.triangle-r {
width: 0;
height: 0;
border-width: 7px 0 7px 7px;
border-style: solid;
border-color: transparent rgb(191, 6, 19) transparent;
margin: 6px 0 0 8px;
}
.triangle-l {
width: 0;
height: 0;
border-width: 7px 7px 7px 0;
border-style: solid;
border-color: transparent rgb(191, 6, 19) transparent;
margin: 6px 8px 0 0;
}
.calendar-detail-head li {
height: 33px;
color: #cccccc;
}
.changeHeight li {
height: 28px ;
line-height: 28px ;
}
.el-select {
width: 80px;
}
</style>