vue3实现日历
Vue3 日历组件实现方法
基础日历结构
使用Vue3的Composition API可以快速构建日历核心逻辑。以下代码展示如何生成当月日历网格:
<script setup>
import { ref, computed } from 'vue'
const currentDate = ref(new Date())
const currentMonth = computed(() => currentDate.value.getMonth())
const currentYear = computed(() => currentDate.value.getFullYear())
const daysInMonth = computed(() => {
return new Date(currentYear.value, currentMonth.value + 1, 0).getDate()
})
const firstDayOfMonth = computed(() => {
return new Date(currentYear.value, currentMonth.value, 1).getDay()
})
const calendarDays = computed(() => {
const days = []
const prevMonthDays = new Date(currentYear.value, currentMonth.value, 0).getDate()
// 上个月末尾几天
for (let i = firstDayOfMonth.value - 1; i >= 0; i--) {
days.push({ day: prevMonthDays - i, isCurrentMonth: false })
}
// 当月所有天
for (let i = 1; i <= daysInMonth.value; i++) {
days.push({ day: i, isCurrentMonth: true })
}
// 下个月开头几天
const remainingCells = 42 - days.length
for (let i = 1; i <= remainingCells; i++) {
days.push({ day: i, isCurrentMonth: false })
}
return days
})
</script>
模板渲染
在模板中使用grid布局展示日历:
<template>
<div class="calendar">
<div class="header">
<button @click="prevMonth">←</button>
<h2>{{ currentDate.toLocaleString('default', { month: 'long', year: 'numeric' }) }}</h2>
<button @click="nextMonth">→</button>
</div>
<div class="weekdays">
<div v-for="day in ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']" :key="day">
{{ day }}
</div>
</div>
<div class="days">
<div
v-for="(dayObj, index) in calendarDays"
:key="index"
:class="{ 'other-month': !dayObj.isCurrentMonth }"
>
{{ dayObj.day }}
</div>
</div>
</div>
</template>
样式设计
添加基础样式使日历更美观:
<style scoped>
.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 div {
text-align: center;
font-weight: bold;
}
.days div {
height: 40px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 4px;
}
.days div.other-month {
opacity: 0.3;
}
.days div:hover {
background-color: #f0f0f0;
cursor: pointer;
}
</style>
功能扩展
实现月份切换和日期选择功能:
const prevMonth = () => {
currentDate.value = new Date(currentYear.value, currentMonth.value - 1, 1)
}
const nextMonth = () => {
currentDate.value = new Date(currentYear.value, currentMonth.value + 1, 1)
}
const selectedDate = ref(null)
const selectDate = (dayObj) => {
if (!dayObj.isCurrentMonth) return
selectedDate.value = new Date(currentYear.value, currentMonth.value, dayObj.day)
}
高级功能实现
添加事件标记和范围选择:
const events = ref([
{ date: '2023-07-15', title: '会议' },
{ date: '2023-07-20', title: '生日' }
])
const hasEvent = (day) => {
const dateStr = `${currentYear.value}-${currentMonth.value + 1}-${day}`
return events.value.some(event => event.date === dateStr)
}
// 模板中修改日期单元格
<div
v-for="(dayObj, index) in calendarDays"
:key="index"
:class="{
'other-month': !dayObj.isCurrentMonth,
'has-event': dayObj.isCurrentMonth && hasEvent(dayObj.day)
}"
@click="selectDate(dayObj)"
>
{{ dayObj.day }}
<span v-if="dayObj.isCurrentMonth && hasEvent(dayObj.day)" class="event-dot"></span>
</div>
响应式改进
使日历适应不同屏幕尺寸:
@media (max-width: 600px) {
.calendar {
width: 100%;
}
.days div {
height: 30px;
}
}
这个实现包含了日历的核心功能,可以根据需要进一步扩展如周视图、年视图、拖拽添加事件等高级功能。组件化的设计使其可以轻松集成到任何Vue3项目中。







