在 Vue 2 中使用 moment
库绘制一个带有上个月和下个月日期的日历,可以通过以下步骤实现。这个日历将显示当前月份的天数,以及前一个月和下一个月的部分日期(通常为了让日历对齐为6行,每行7天)。
主要步骤:
- 生成当前月份的所有天数。
- 计算上个月的剩余天数(即填充当前月份开始前的日期)。
- 计算下个月的天数(即填充当前月份结束后的日期,直到日历的最后一天)
实现效果
代码实现
- 安装
moment
库
首先,确保已经安装moment
库:
npm install moment
- 在 Vue 组件中绘制日历
<template><div class="calendar"><div class="calendar-top flex"><div class="calendar-top-same"><div>{{ month.format("YYYY年MM月") }}</div></div><el-button @click="prevMonth" size="mini">上个月</el-button><el-button @click="currentMonth" size="mini">今天</el-button><el-button @click="nextMonth" size="mini">下个月</el-button></div><div class="calendar-body"><div v-for="item in weekdays" :key="item" class="calendar-body-week">{{ item }}</div><divv-for="(day, index) in days":key="index"class="calendar-body-day":class="{dis: day.isPrevMonth||day.isNextMonth,today:today===day.date.format('YYYY-MM-DD')}"@click="handleClickDay(day)">{{ day.date.date() }}</div></div></div>
</template><script>
import moment from "moment";
export default {name: "calendar",props: {// 日期date: {type: Date,default() {return new Date();},},},data() {return {today: '', // 选中的日期month: moment(), // 当前月份weekdays: ["日", "一", "二", "三", "四", "五", "六"], // 星期days: [], // 存储当前日历显示的天数};},mounted() {this.today = moment(this.date).format("YYYY-MM-DD");this.generateCalendar();},methods: {// 生成日历generateCalendar() {this.days = [];// 获取当前月份的开始和结束日期const startOfMonth = this.month.clone().startOf("month");const endOfMonth = this.month.clone().endOf("month");// 获取上个月需要显示的天数const startWeekday = startOfMonth.day();const prevMonthDays = [];if (startWeekday > 0) {const prevMonthEnd = startOfMonth.clone().subtract(1, "month").endOf("month");for (let i = startWeekday - 1; i >= 0; i--) {prevMonthDays.push({date: prevMonthEnd.clone().subtract(i, "days"),isPrevMonth: true,});}}// 获取当前月份的所有天数const currentMonthDays = [];for (let i = 0; i < endOfMonth.date(); i++) {currentMonthDays.push({date: startOfMonth.clone().add(i, "days"),isPrevMonth: false,isNextMonth: false,// 是否为今天isToday: startOfMonth.clone().add(i, "days").isSame(moment(), "day"),// 是否为今天之后的日期 不含今天isAfterToday: startOfMonth.clone().add(i, "days").isAfter(moment(),"day",)});}// 获取下个月需要显示的天数const endWeekday = endOfMonth.day();const nextMonthDays = [];if (endWeekday < 6) {for (let i = 1; i <= 6 - endWeekday; i++) {nextMonthDays.push({date: endOfMonth.clone().add(i, "days"),isNextMonth: true,isAfterToday: endOfMonth.clone().add(i, "days").isAfter(moment(),"day",)});}}// 合并上个月、当前月份、下个月的天数this.days = [...prevMonthDays, ...currentMonthDays, ...nextMonthDays];},// 切换到上个月prevMonth() {this.month = this.month.clone().subtract(1, "month");this.generateCalendar();},// 切换到当前月份currentMonth() {this.today = moment().format("YYYY-MM-DD");this.month = moment();this.generateCalendar();this.$emit("change",this.today)},// 切换到下个月nextMonth() {this.month = this.month.clone().add(1, "month");this.generateCalendar();},// 今天之前触发handleClickDay(day){if(day.isAfterToday) return;this.today = day.date.format("YYYY-MM-DD");this.$emit("change",this.today)}},
};
</script><style lang="scss" scoped>
.calendar {user-select: none;&-top {justify-content: space-between;border: 1px solid #ccc;align-items: center;font-size: 14px;&-same {flex: 1;text-align: center;}}&-body {font-size: 14px;padding: 5px;display: grid;grid-template-columns: repeat(7, 1fr);&-week {background: #f5f7fa;cursor: progress;}> div {margin: 2px;text-align: center;border: #ccc solid 1px;padding: 5px;}&-day {cursor: pointer;.km {font-size: 12px;line-height: 1;color: #333;}&.dis {color: #ccc;// cursor: not-allowed;}&.today {background: #66b1ff;color: #fff;}}}
}
</style>
解释:
today
:当前选中的日期,默认今天month
:使用moment
来追踪当前月份。generateCalendar
:这个方法用来生成日历,包括上个月的部分日期、当前月份的日期和下个月的部分日期。prevMonth
和nextMonth
: 点击按钮来切换月份。currentMonth
:这个方法是用来跳回到今天。