vue 实现日历
Vue 日历组件实现
基础日历结构
使用 Vue 的模板和数据绑定功能创建日历骨架。需要定义当前年份、月份,并生成对应的日期数组。
<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>
<script>
export default {
data() {
return {
weekdays: ['日', '一', '二', '三', '四', '五', '六'],
currentYear: new Date().getFullYear(),
currentMonth: new Date().getMonth(),
}
},
computed: {
days() {
// 生成当月日期数组的逻辑
}
},
methods: {
prevMonth() {
// 上个月逻辑
},
nextMonth() {
// 下个月逻辑
}
}
}
</script>
<style>
.calendar {
width: 100%;
max-width: 600px;
margin: 0 auto;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
}
.weekdays, .days {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
.days div {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
}
.other-month {
color: #ccc;
}
</style>
日期生成逻辑
在 computed 属性中完善 days 计算逻辑,生成包含当月日期及前后月份补全的日期数组。
computed: {
days() {
const firstDay = new Date(this.currentYear, this.currentMonth, 1)
const lastDay = new Date(this.currentYear, this.currentMonth + 1, 0)
const daysInMonth = lastDay.getDate()
const firstDayOfWeek = firstDay.getDay()
const days = []
// 添加上个月末尾的几天
const prevMonthDays = firstDayOfWeek
if (prevMonthDays > 0) {
const prevMonthLastDay = new Date(this.currentYear, this.currentMonth, 0).getDate()
for (let i = prevMonthLastDay - prevMonthDays + 1; i <= prevMonthLastDay; i++) {
days.push({
date: i,
isCurrentMonth: false
})
}
}
// 添加当月所有日期
for (let i = 1; i <= daysInMonth; i++) {
days.push({
date: i,
isCurrentMonth: true
})
}
// 添加下个月开始的几天
const totalCells = prevMonthDays + daysInMonth
const nextMonthDays = totalCells <= 35 ? 35 - totalCells : 42 - totalCells
for (let i = 1; i <= nextMonthDays; i++) {
days.push({
date: i,
isCurrentMonth: false
})
}
return days
}
}
月份切换功能
实现月份切换方法,确保年份也会相应变化。
methods: {
prevMonth() {
if (this.currentMonth === 0) {
this.currentMonth = 11
this.currentYear--
} else {
this.currentMonth--
}
},
nextMonth() {
if (this.currentMonth === 11) {
this.currentMonth = 0
this.currentYear++
} else {
this.currentMonth++
}
}
}
日期选择功能
添加日期选择功能,记录选中的日期并高亮显示。
<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: {
selectDate(day) {
if (day.isCurrentMonth) {
this.selectedDate = new Date(this.currentYear, this.currentMonth, day.date)
}
},
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
}
}
.selected {
background-color: #42b983;
color: white;
border-radius: 50%;
}
高级功能扩展
可以进一步扩展日历组件功能:
- 添加事件标记功能,在特定日期显示标记点
- 实现范围选择,允许选择开始和结束日期
- 添加周视图切换功能
- 集成日期选择器弹出框
- 支持多语言和本地化设置
// 事件标记示例
data() {
return {
events: {
'2023-11-15': '会议',
'2023-11-20': '生日'
}
}
},
methods: {
hasEvent(day) {
if (!day.isCurrentMonth) return false
const dateStr = `${this.currentYear}-${this.currentMonth + 1}-${day.date}`
return this.events[dateStr]
}
}
<div class="day-cell" @click="selectDate(day)">
{{ day.date }}
<div v-if="hasEvent(day)" class="event-dot"></div>
</div>
.event-dot {
width: 6px;
height: 6px;
background-color: #f00;
border-radius: 50%;
position: absolute;
bottom: 5px;
left: 50%;
transform: translateX(-50%);
}






