Vue 中如何实现日期范围选择器?
日期范围选择器是现代 Web 应用程序中经常用到的一种界面组件。它允许用户从一个日期范围中选择一个日期或者一个时间段。对于需求为日期范围选择器的 Web 应用程序开发,Vue.js 是一个非常好的选择。
Vue.js 是一个用于构建用户界面的渐进式 JavaScript 框架,它允许开发者使用组件化的方式来构建复杂的交互式界面。在这篇文章中,我们将介绍如何使用 Vue.js 来创建一个日期范围选择器组件。
- 组件结构
首先,让我们来定义一下组件的结构。我们需要一个包含两个选择器的容器,一个用于选择开始日期,另一个用于选择结束日期。这两个选择器都应该包括一个日历组件和一个输入框,用户可以在输入框中直接输入日期,也可以通过日历选择器来选择日期。
在 Vue 中,组件通常采用树形结构来组织,我们可以定义一个父组件,然后将两个日期选择器组件作为它的子组件。父组件负责管理数据,子组件负责展示数据和与用户交互。代码如下:
<template>
<div>
<date-selector v-model="startDate"></date-selector>
<date-selector v-model="endDate"></date-selector>
</div>
</template>
<script>
import DateSelector from './DateSelector.vue'
export default {
components: {
DateSelector
},
data () {
return {
startDate: '',
endDate: ''
}
}
}
</script>- 日历组件
接下来,让我们来实现日历组件。这个组件将允许用户在一个日历中选择日期,并将选择的日期显示在输入框中。我们可以使用 Vue.js 的 v-model 指令来实现输入框和数据绑定。代码如下:
<template>
<div class="date-selector">
<input :value="dateString" @blur="handleChange" @keydown.enter="handleChange">
<svg @click="showCalendar" class="icon icon-calendar">
<use xlink:href="#calendar" />
</svg>
<div v-if="show" class="date-calendar">
<calendar :date="date" @change="updateDate"></calendar>
</div>
</div>
</template>
<script>
import Calendar from './Calendar.vue'
export default {
components: {
Calendar
},
props: {
value: {
type: String,
default: ''
}
},
data () {
return {
date: new Date(),
show: false
}
},
computed: {
dateString () {
return this.value || ''
}
},
methods: {
handleChange (event) {
const dateString = event.target.value.trim()
if (dateString) {
const date = new Date(dateString)
if (!isNaN(date.getTime())) {
this.date = date
}
}
this.$emit('input', dateString)
},
showCalendar () {
this.show = true
},
updateDate (date) {
this.date = date
this.show = false
this.$emit('input', this.date.toISOString().slice(0, 10))
}
}
}
</script>可以看到,这个组件包含一个输入框和一个表示日历的 SVG 图标。用户点击 SVG 图标时,将会显示一个日历组件。在日历组件中选择日期后,日期范围选择器将更新数据,并将日期字符串传递到父组件中。
- 日历组件的核心 - 日历显示和交互
最后,让我们来实现一个日历组件。由于我们的目标是实现一个日期范围选择器,因此我们将仅实现日期选择,并将禁用时间选择。我们将使用 HTML 的 table 元素来构建日历,使用 CSS 来实现样式。代码如下:
<template>
<div class="calendar">
<div class="calendar-header">
<button class="calendar-btn" @click.prevent="prevMonth"><</button>
<span class="calendar-month">{{month}} {{year}}</span>
<button class="calendar-btn" @click.prevent="nextMonth">></button>
</div>
<table>
<thead>
<tr>
<th>Sun</th>
<th>Mon</th>
<th>Tue</th>
<th>Wed</th>
<th>Thu</th>
<th>Fri</th>
<th>Sat</th>
</tr>
</thead>
<tbody>
<tr v-for="week in weeks" :key="week">
<td v-for="date in week" :key="date" @click.prevent="updateDate(date)">
<div :class="{ 'calendar-date': true, 'calendar-date--selected': isDateSelected(date), 'calendar-date--disabled': isDateDisabled(date) }">{{date.getDate()}}</div>
</td>
</tr>
</tbody>
</table>
</div>
</template>
<script>
export default {
props: {
date: Date
},
data () {
return {
year: this.date.getFullYear(),
month: this.date.toLocaleString('default', { month: 'long' }),
selectedDate: this.date
}
},
computed: {
weeks () {
const weeks = []
const firstDayOfMonth = new Date(this.year, this.date.getMonth(), 1)
const lastDayOfMonth = new Date(this.year, this.date.getMonth() + 1, 0)
const daysInMonth = lastDayOfMonth.getDate()
const firstDayOfWeek = firstDayOfMonth.getDay()
let week = []
for (let i = 0; i < firstDayOfWeek; i++) {
week.push(new Date(this.year, this.date.getMonth(), i - firstDayOfWeek + 1))
}
for (let i = 1; i <= daysInMonth; i++) {
week.push(new Date(this.year, this.date.getMonth(), i))
if (week.length === 7) {
weeks.push(week)
week = []
}
}
if (week.length > 0) {
for (let i = week.length; i < 7; i++) {
week.push(new Date(this.year, this.date.getMonth() + 1, i - firstDayOfWeek + 1))
}
weeks.push(week)
}
return weeks
}
},
methods: {
prevMonth () {
if (this.date.getMonth() === 0) {
this.year--
this.month = 'December'
} else {
this.month = this.date.toLocaleString('default', { month: 'long', monthIndex: 'numeric' })
}
this.date.setMonth(this.date.getMonth() - 1)
},
nextMonth () {
if (this.date.getMonth() === 11) {
this.year++
this.month = 'January'
} else {
this.month = this.date.toLocaleString('default', { month: 'long' })
}
this.date.setMonth(this.date.getMonth() + 1)
},
isDateSelected (date) {
return date.toDateString() === this.selectedDate.toDateString()
},
isDateDisabled (date) {
return date.getMonth() !== this.date.getMonth()
},
updateDate (date) {
if (!this.isDateDisabled(date)) {
this.selectedDate = date
this.$emit('change', date)
}
}
}
}
</script>可以看到,这段代码包含一个计算属性 weeks,它是一个数组,每个数组元素代表一个星期。对于每个星期,我们使用 v-for 指令来构建日期单元格。我们通过 isDateSelected 和 isDateDisabled 方法来确定日期是否被选择或被禁用。同时,我们使用 updateDate 方法来更新日期并通知父组件这个事件。
至此,我们已经完成了 Vue.js 中的日期范围选择器组件。这个组件支持语言环境并允许用户选择日期范围,可以方便地应用于各种应用程序中。
