<template>
<div>
<!-- 输入框和日历图标 -->
<input type="text" v-model="selectedDate" @focus="showCalendar" readonly>
<span @click="showCalendar">📅</span>
<!-- 日历选择器 -->
<div v-if="isCalendarVisible" class="calendar" >
<div class="calendar-header">
<button @click="previousMonth"><</button>
<span>{{ currentMonth }}</span>
<button @click="nextMonth">></button>
</div>
<div class="calendar-body">
<div class="weekdays">
<span v-for="day in daysOfWeek" :key="day">{{ day }}</span>
</div>
<div class="dates">
<span v-for="date in datesInMonth" :key="date"
@mouseenter="hoverDate(date)" @mouseleave="clearHover"
@click="selectDate(date)"
:class="{ 'hovered': date === hoveredDate, 'selected': date === selectedDate }">{{ date }}</span>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
selectedDate: '', // 选定的日期
isCalendarVisible: false, // 日历是否可见
currentDate: new Date(), // 当前日期
hoveredDate: '', // 悬浮的日期
daysOfWeek: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] // 一周的日期
};
},
computed: {
currentMonth() {
return this.currentDate.toLocaleString('default', { month: 'long', year: 'numeric' });
},
datesInMonth() {
const year = this.currentDate.getFullYear();
const month = this.currentDate.getMonth();
const firstDayOfMonth = new Date(year, month, 1);
const lastDayOfMonth = new Date(year, month + 1, 0);
const dates = [];
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
dates.push(i);
}
// 补充前面的空白日期
for (let i = 0; i < firstDayOfMonth.getDay(); i++) {
dates.unshift('');
}
return dates;
}
},
methods: {
showCalendar() {
this.isCalendarVisible = true;
document.addEventListener('mousedown', this.handleClickOutside);
},
hideCalendar() {
this.isCalendarVisible = false;
document.removeEventListener('mousedown', this.handleClickOutside);
},
handleClickOutside(event) {
if (this.$el && !this.$el.contains(event.target)) {
this.hideCalendar();
}
},
previousMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() - 1);
this.currentDate = new Date(this.currentDate); // 触发依赖于 currentDate 的计算属性更新
},
nextMonth() {
this.currentDate.setMonth(this.currentDate.getMonth() + 1);
this.currentDate = new Date(this.currentDate); // 触发依赖于 currentDate 的计算属性更新
},
selectDate(date) {
if (date !== '') {
const year = this.currentDate.getFullYear();
const month = this.currentDate.getMonth() + 1;
const formattedDate = `${year}-${month < 10 ? '0' + month : month}-${date < 10 ? '0' + date : date}`;
this.selectedDate = formattedDate;
this.hideCalendar();
}
},
hoverDate(date) {
if (!isNaN(date)) {
this.hoveredDate = date;
}
},
clearHover() {
this.hoveredDate = '';
}
},
beforeDestroy() {
document.removeEventListener('mousedown', this.handleClickOutside);
}
};
</script>
<style scoped>
.calendar {
position: absolute;
background-color: #fff;
border: 1px solid #ccc;
padding: 10px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.calendar-header {
display: flex;
justify-content: space-between;
align-items: center;
}
.calendar-header button {
background-color: transparent;
border: none;
cursor: pointer;
font-size: 14px;
}
.weekdays {
display: flex;
justify-content: space-between;
padding: 5px 0;
}
.weekdays span {
width: calc(100% / 7);
text-align: center;
}
.dates {
display: flex;
flex-wrap: wrap;
}
.dates span {
width: calc(100% / 7);
text-align: center;
padding: 5px 0;
cursor: pointer;
}
.dates span.hovered {
background-color: #f0f0f0;
}
.dates span.selected {
color: #fff;
}
</style>