<template>
<div class="calendar">
<div class="header">
<span @click="prevMonth"><</span>
<h2>{{ year }}年{{ month }}月</h2>
<span @click="nextMonth">></span>
</div>
<div class="box">
<div class="box-top">
<div class="box-top-content">
<div>日</div>
<div>一</div>
<div>二</div>
<div>三</div>
<div>四</div>
<div>五</div>
<div>六</div>
</div>
</div>
<div class="box-bottom">
<div class="box-bottom-content" v-for="(week, index) in weeks" :key="index">
<div class="box-bottom-content-box" v-for="(day, i) in week" :key="i" :class="{ today: day.today, selected: day.selected }" @click="selectDay(day)">
{{ day.date && day.date.getDate() }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
year: 2021,
month: 1,
selectedDate: null,
};
},
computed: {
weeks() {
const weeks = [];
const firstDayOfMonth = new Date(this.year, this.month - 1, 1);
const lastDayOfMonth = new Date(this.year, this.month, 0);
const daysInMonth = lastDayOfMonth.getDate();
let dayOfWeek = firstDayOfMonth.getDay();
let date = 1;
for (let i = 0; i < 6; i++) {
const week = [];
for (let j = 0; j < 7; j++) {
if (i === 0 && j < dayOfWeek) {
week.push({ date: null });
} else if (date > daysInMonth) {
week.push({ date: null });
} else {
const today = new Date();
const selected = this.selectedDate && this.selectedDate.getTime() === new Date(this.year, this.month - 1, date).getTime();
week.push({ date: new Date(this.year, this.month - 1, date), today: today.getTime() === new Date(this.year, this.month - 1, date).getTime(), selected });
date++;
}
}
weeks.push(week);
}
return weeks.filter((e, i) => i === 5 ? !!e[0].date : true);
},
},
methods: {
prevMonth() {
if (this.month === 1) {
this.year--;
this.month = 12;
} else {
this.month--;
}
},
nextMonth() {
if (this.month === 12) {
this.year++;
this.month = 1;
} else {
this.month++;
}
},
selectDay(day) {
if (day.date) {
this.selectedDate = day.date;
}
},
},
};
</script>
<style>
.calendar {
font-family: Arial, sans-serif;
width: 238px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
height: 34px;
}
.header span {
background-color: transparent;
font-size: 18px;
}
.box {
width: 100%;
border-collapse: collapse;
padding: 0;
}
.box-top-content {
display: flex;
justify-content: space-between;
}
.box-top-content > div {
width: 34px;
height: 34px;
display: flex;
justify-content: center;
align-items: center;
}
.box-bottom {
display: flex;
flex-direction: column;
}
.box-bottom-content {
display: flex;
justify-content: space-between;
}
.box-bottom-content-box {
width: 34px;
height: 34px;
display: flex;
justify-content: center;
align-items: center;
}
.today {
background-color: #eee;
}
.selected {
background-color: #007bff;
color: #fff;
border-radius: 50%;
}
</style>
效果如下