基于vue实现日历
实现基础日历结构
使用Vue的模板语法构建日历的HTML结构,通常包含星期标题和日期格子。月份切换按钮通过v-on绑定事件。
<template>
<div class="calendar">
<div class="header">
<button @click="prevMonth">上一月</button>
<h2>{{ currentYear }}年{{ currentMonth + 1 }}月</h2>
<button @click="nextMonth">下一月</button>
</div>
<div class="weekdays">
<div v-for="day in weekdays" :key="day">{{ day }}</div>
</div>
<div class="days">
<div
v-for="(day, index) in days"
:key="index"
:class="{ 'other-month': !day.isCurrentMonth }"
>
{{ day.date }}
</div>
</div>
</div>
</template>
处理日历数据逻辑
在Vue的data或setup中定义响应式变量,使用JavaScript的Date对象计算当月天数、上月剩余天数及下月补全天数。

export default {
data() {
return {
currentDate: new Date(),
weekdays: ['日', '一', '二', '三', '四', '五', '六']
}
},
computed: {
currentYear() {
return this.currentDate.getFullYear()
},
currentMonth() {
return this.currentDate.getMonth()
},
days() {
const year = this.currentYear
const month = this.currentMonth
const firstDay = new Date(year, month, 1)
const lastDay = new Date(year, month + 1, 0)
const daysInMonth = lastDay.getDate()
const firstDayOfWeek = firstDay.getDay()
// 生成当月天数数组
const days = []
for (let i = 1; i <= daysInMonth; i++) {
days.push({ date: i, isCurrentMonth: true })
}
// 补全上月剩余天数
const prevMonthDays = firstDayOfWeek
const prevMonthLastDay = new Date(year, month, 0).getDate()
for (let i = 0; i < prevMonthDays; i++) {
days.unshift({ date: prevMonthLastDay - i, isCurrentMonth: false })
}
// 补全下月天数(保持6行)
const totalCells = Math.ceil(days.length / 7) * 7
const nextMonthDays = totalCells - days.length
for (let i = 1; i <= nextMonthDays; i++) {
days.push({ date: i, isCurrentMonth: false })
}
return days
}
}
}
实现月份切换功能
添加月份切换方法,注意处理跨年情况。使用setMonth会自动处理月份溢出(如month=12会变成下一年1月)。

methods: {
prevMonth() {
this.currentDate = new Date(
this.currentYear,
this.currentMonth - 1,
1
)
},
nextMonth() {
this.currentDate = new Date(
this.currentYear,
this.currentMonth + 1,
1
)
}
}
添加样式美化日历
使用CSS Grid布局使日历排列整齐,为不同状态的日期添加视觉区分。
.calendar {
width: 350px;
font-family: Arial;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.weekdays, .days {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
}
.weekdays {
font-weight: bold;
text-align: center;
}
.days div {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.days div.other-month {
opacity: 0.3;
}
扩展功能:日期选择
添加日期选择功能,通过v-model绑定选中的日期,高亮显示当前选中日期。
<div
v-for="(day, index) in days"
:key="index"
:class="{
'other-month': !day.isCurrentMonth,
'selected': isSelected(day)
}"
@click="selectDate(day)"
>
{{ day.date }}
</div>
data() {
return {
selectedDate: null
}
},
methods: {
isSelected(day) {
if (!this.selectedDate || !day.isCurrentMonth) return false
return (
this.selectedDate.getDate() === day.date &&
this.selectedDate.getMonth() === this.currentMonth &&
this.selectedDate.getFullYear() === this.currentYear
)
},
selectDate(day) {
if (!day.isCurrentMonth) return
this.selectedDate = new Date(
this.currentYear,
this.currentMonth,
day.date
)
}
}
.days div.selected {
background-color: #42b983;
color: white;
}






