vue日历组件实现
Vue 日历组件实现方法
基础日历结构
使用 Vue 的模板语法构建日历骨架,通过 v-for 循环渲染日期格子。核心是计算当前月份的天数和起始星期位置。
<template>
<div class="calendar">
<div class="header">
<button @click="prevMonth">上个月</button>
<span>{{ currentYear }}年{{ currentMonth + 1 }}月</span>
<button @click="nextMonth">下个月</button>
</div>
<div class="weekdays">
<div v-for="day in ['日','一','二','三','四','五','六']" :key="day">{{ day }}</div>
</div>
<div class="days">
<div
v-for="(day, index) in days"
:key="index"
:class="{ 'other-month': !day.isCurrentMonth }"
@click="selectDay(day)"
>
{{ day.date.getDate() }}
</div>
</div>
</div>
</template>
日期计算逻辑
在 Vue 的 data 或 setup 中定义响应式变量,通过计算方法生成当月日历数据:
export default {
data() {
return {
currentDate: new Date(),
days: []
}
},
computed: {
currentYear() {
return this.currentDate.getFullYear()
},
currentMonth() {
return this.currentDate.getMonth()
}
},
methods: {
generateDays() {
const year = this.currentYear
const month = this.currentMonth
const firstDay = new Date(year, month, 1)
const lastDay = new Date(year, month + 1, 0)
const startDay = firstDay.getDay()
const totalDays = lastDay.getDate()
const daysArray = []
// 上个月末尾几天
const prevMonthLastDay = new Date(year, month, 0).getDate()
for (let i = 0; i < startDay; i++) {
daysArray.push({
date: new Date(year, month - 1, prevMonthLastDay - i),
isCurrentMonth: false
})
}
daysArray.reverse()
// 当月日期
for (let i = 1; i <= totalDays; i++) {
daysArray.push({
date: new Date(year, month, i),
isCurrentMonth: true
})
}
// 下个月开头几天
const remaining = 42 - daysArray.length
for (let i = 1; i <= remaining; i++) {
daysArray.push({
date: new Date(year, month + 1, i),
isCurrentMonth: false
})
}
this.days = daysArray
},
prevMonth() {
this.currentDate = new Date(this.currentYear, this.currentMonth - 1, 1)
this.generateDays()
},
nextMonth() {
this.currentDate = new Date(this.currentYear, this.currentMonth + 1, 1)
this.generateDays()
},
selectDay(day) {
console.log('Selected:', day.date)
}
},
mounted() {
this.generateDays()
}
}
样式增强
添加基础样式使日历更美观:
.calendar {
width: 350px;
border: 1px solid #eee;
font-family: Arial;
}
.header {
display: flex;
justify-content: space-between;
padding: 10px;
background: #f5f5f5;
}
.weekdays, .days {
display: grid;
grid-template-columns: repeat(7, 1fr);
}
.weekdays div {
padding: 10px;
text-align: center;
font-weight: bold;
}
.days div {
padding: 10px;
height: 40px;
text-align: center;
border-bottom: 1px solid #eee;
cursor: pointer;
}
.days div.other-month {
color: #ccc;
}
.days div:hover {
background: #f0f0f0;
}
高级功能扩展
- 日期范围选择:添加
startDate和endDate状态,通过比较逻辑标记选中范围 - 事件标记:接收外部事件数据,在日期格子上显示标记点
- 国际化:支持多语言星期显示和日期格式
- 自定义插槽:允许用户自定义日期格子的渲染内容
// 范围选择示例
methods: {
isInRange(date) {
if (!this.startDate || !this.endDate) return false
return date >= this.startDate && date <= this.endDate
},
handleDayClick(day) {
if (!this.startDate || (this.startDate && this.endDate)) {
this.startDate = day.date
this.endDate = null
} else {
this.endDate = day.date
if (this.endDate < this.startDate) {
[this.startDate, this.endDate] = [this.endDate, this.startDate]
}
}
}
}
第三方库方案
对于生产环境,可以考虑以下成熟库:
- Vue DatePicker:轻量级且高度可配置
- FullCalendar:功能全面的日历组件,支持拖拽等高级功能
- V-Calendar:提供丰富的日期选择器和日历视图
安装示例:
npm install v-calendar
基础使用:
import VCalendar from 'v-calendar'
// 在组件中
<v-calendar :attributes="attributes" />
以上方案可根据实际需求组合使用,基础实现约100行代码即可完成核心功能,扩展功能需根据具体场景增加相应逻辑。







