vue封装datepicker实现
vue封装datepicker实现
基础组件结构
使用Vue的单文件组件形式封装DatePicker,核心结构包含模板、脚本和样式三部分。模板部分定义日期选择器的UI布局,脚本处理逻辑,样式负责外观。
模板部分示例:

<template>
<div class="date-picker">
<input
type="text"
v-model="displayValue"
@click="togglePicker"
@blur="handleBlur"
/>
<div class="calendar" v-show="isOpen">
<div class="header">
<button @click="prevMonth">‹</button>
<span>{{ currentMonth }}</span>
<button @click="nextMonth">›</button>
</div>
<div class="days">
<div v-for="day in days" :key="day" class="day-header">{{ day }}</div>
</div>
<div class="dates">
<div
v-for="date in visibleDates"
:key="date.getTime()"
@click="selectDate(date)"
:class="{
'selected': isSelected(date),
'current-month': isCurrentMonth(date),
'today': isToday(date)
}"
>
{{ date.getDate() }}
</div>
</div>
</div>
</div>
</template>
核心逻辑实现
脚本部分处理日期选择的核心功能,包括日期生成、月份切换和选择逻辑。

<script>
export default {
data() {
return {
selectedDate: null,
currentDate: new Date(),
isOpen: false,
days: ['日', '一', '二', '三', '四', '五', '六']
}
},
computed: {
displayValue() {
return this.selectedDate
? `${this.selectedDate.getFullYear()}-${this.selectedDate.getMonth() + 1}-${this.selectedDate.getDate()}`
: '';
},
currentMonth() {
return `${this.currentDate.getFullYear()}年${this.currentDate.getMonth() + 1}月`;
},
visibleDates() {
const dates = [];
const firstDay = new Date(
this.currentDate.getFullYear(),
this.currentDate.getMonth(),
1
);
const lastDay = new Date(
this.currentDate.getFullYear(),
this.currentDate.getMonth() + 1,
0
);
const prevMonthDays = firstDay.getDay();
const nextMonthDays = 6 - lastDay.getDay();
const startDate = new Date(firstDay);
startDate.setDate(startDate.getDate() - prevMonthDays);
const endDate = new Date(lastDay);
endDate.setDate(endDate.getDate() + nextMonthDays);
while (startDate <= endDate) {
dates.push(new Date(startDate));
startDate.setDate(startDate.getDate() + 1);
}
return dates;
}
},
methods: {
togglePicker() {
this.isOpen = !this.isOpen;
},
handleBlur() {
setTimeout(() => {
this.isOpen = false;
}, 200);
},
prevMonth() {
this.currentDate = new Date(
this.currentDate.getFullYear(),
this.currentDate.getMonth() - 1,
1
);
},
nextMonth() {
this.currentDate = new Date(
this.currentDate.getFullYear(),
this.currentDate.getMonth() + 1,
1
);
},
selectDate(date) {
this.selectedDate = date;
this.$emit('input', date);
this.isOpen = false;
},
isSelected(date) {
return this.selectedDate &&
date.getFullYear() === this.selectedDate.getFullYear() &&
date.getMonth() === this.selectedDate.getMonth() &&
date.getDate() === this.selectedDate.getDate();
},
isCurrentMonth(date) {
return date.getMonth() === this.currentDate.getMonth();
},
isToday(date) {
const today = new Date();
return date.getFullYear() === today.getFullYear() &&
date.getMonth() === today.getMonth() &&
date.getDate() === today.getDate();
}
}
}
</script>
样式优化
添加基础样式增强用户体验,包括日历布局、日期状态样式和过渡效果。
<style scoped>
.date-picker {
position: relative;
display: inline-block;
}
input {
padding: 8px;
border: 1px solid #ddd;
border-radius: 4px;
}
.calendar {
position: absolute;
top: 100%;
left: 0;
width: 280px;
margin-top: 5px;
padding: 10px;
background: white;
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
z-index: 1000;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
}
.days {
display: grid;
grid-template-columns: repeat(7, 1fr);
margin-bottom: 5px;
}
.day-header {
text-align: center;
font-weight: bold;
}
.dates {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 5px;
}
.dates > div {
text-align: center;
padding: 5px;
cursor: pointer;
border-radius: 3px;
}
.dates > div:hover {
background: #f0f0f0;
}
.dates > div.current-month {
color: #333;
}
.dates > div:not(.current-month) {
color: #aaa;
}
.dates > div.selected {
background: #409eff;
color: white;
}
.dates > div.today {
font-weight: bold;
color: #409eff;
}
</style>
组件使用方式
封装完成后,可以在父组件中直接使用,并通过v-model绑定日期值。
<template>
<div>
<date-picker v-model="selectedDate" />
</div>
</template>
<script>
import DatePicker from './DatePicker.vue';
export default {
components: { DatePicker },
data() {
return {
selectedDate: null
}
}
}
</script>
功能扩展建议
- 添加日期范围选择功能
- 支持国际化显示
- 增加日期禁用功能
- 添加动画过渡效果
- 支持自定义日期格式
通过以上步骤可以实现一个基础的Vue日期选择器组件,根据实际需求可以进一步扩展功能。组件化的设计使其易于复用和维护,样式部分使用scoped避免污染全局样式。






