实现效果:
代码:
引入momentjs然后封装两个函数构建出基本数据结构
import moment from 'moment';// 某月有多少天
export const getEndDay = (m) => m.daysInMonth();/*** @description 获取本月空值数据* @param { Date } year { } 年度* @param { Number } month 月份* @param { Date } current moment当天日期*/
export const getCalendar = ({ year, month, current }) => {// 最多6行, 每行为一周7天const totalDays = 7 * 6;// 获取这个月第一天具体日期const start = new Date(year, month - 1, 1);let lastEndDay = [];// 上个月的天数const lastDays = getEndDay(current.clone().subtract(1, 'month'));// 当前月的天数const nowDays = getEndDay(current);const currentDays = [...(new Array(nowDays))].map((v, i) => ({day: i + 1,})).map((v) => {const currentDate = v.day >= 10 ? `${moment(current).format('YYYY-MM')}-${v.day}` : `${moment(current).format('YYYY-MM')}-0${v.day}`;return {day: v.day,denyTime: moment().valueOf() > moment(`${currentDate} 23:59:59`).valueOf(),currentDate,};});if (start.getDay() === 0) {// 这个月1号为周日,则取上个月最后6天lastEndDay = [...new Array(lastDays)].map((v, i) => i + 1).filter((v) => v > lastDays - 6).map((v) => ({day: v,denyMonth: true,}));} else {lastEndDay = [...(new Array(lastDays))].map((v, i) => i + 1).filter((v, i) => i > lastDays - start.getDay()).map((v) => ({day: v,denyMonth: true,}));}// 获取下个月补充天数const nextDays = [...new Array(totalDays - lastEndDay.length - currentDays.length)].map((v, i) => ({ day: i + 1, denyMonth: true }));const data = [...lastEndDay, ...currentDays, ...nextDays];return data;
};
页面代码部分:
<template><div><div class="flex-y-center flex-x-between border-t border-r border-l pad-y-xs pad-x-md"><div>{{ renderCalendarMonth }}</div><div class="text-right"><el-button size="small" @click="handleMonth(1)">上个月</el-button><el-button size="small" @click="handleMonth()">本月</el-button><el-button size="small" @click="handleMonth(2)">下个月</el-button></div></div><div class="border-a pad-a-sm"><div class="grid-week mar-b-sm"><div v-for="item in weekLabel" :key="item" class="text-center">{{ item }}</div></div><div class="grid-month-day"><divv-for="(item, idx) in CalendarDays":key="idx":class="{'text-center': 1,'grey-out-ban': item.denyMonth || item.denyTime,'active': item.currentDate === activeDay}"@click="handleDay(item)">{{ item.day }}</div></div></div>
</div>
</template>import moment from 'moment';
import { getCalendar } from '../request';export default {data() {return {weekLabel: ['一', '二', '三', '四', '五', '六', '七'],// 当前时间日历推导currentTime: moment(),// 日历挂表CalendarDays: [],// 选择日期activeDay: moment().format('yyyy-MM-DD'),// 月份切换activeMonth: 0,};},
computed: {// 日历具体年月份renderCalendarMonth() {const enumMonth = ['一', '二', '三', '四', '五', '六', '七', '八', '九', '十', '十一', '十二'];const year = moment().subtract(this.activeMonth, 'months').format('yyyy');let month = moment().subtract(this.activeMonth, 'months').format('M');month = enumMonth[month - 1];return `${year}年${month}月`;},},
created() {this.init();},methods: {// 初始化init() {this.CalendarDays = getCalendar({year: moment().format('yyyy'), current: this.currentTime, month: moment().format('M'),});},// 月份切换handleMonth(type) {if (type) {if (type === 1) {this.activeMonth++;} else {this.activeMonth--;}const day = moment().subtract(this.activeMonth, 'months');this.CalendarDays = getCalendar({year: day.format('yyyy'),current: day,month: day.format('M'),});} else {this.activeMonth = 0;this.CalendarDays = getCalendar({year: moment().format('yyyy'), current: this.currentTime, month: moment().format('M'),});this.activeDay = moment().format('yyyy-MM-DD');}},handleDay(item) {if (item.denyMonth || item.denyTime) return;this.activeDay = item.currentDate;},},};
</script><style lang="scss" scoped>
.grid-week, .grid-month-day {display: grid;grid-template-columns: repeat(7, 1fr);gap: 10px;
}.grid-month-day {&>div {padding: 6px 0;box-sizing: border-box;border: 1px solid $base-border-color;&.grey-out-ban {background-color: #E9E9EB;cursor: not-allowed;}&:not(.grey-out-ban) {color: $base-color-primary;cursor: pointer;}&.active {border: 1px solid $base-color-primary;background-color: $base-color-primary;color: white;}}
}
</style>
结尾:这里贴代码就挺难受的,没有Vue只有html,果然这个时候用react就不错,不过思路已经提供了,先理清日历的每周对应天数结构,后面处理起来就容易许多。这里附上做的另一个日历效果图,代码就不贴了,js推导函数都差不多,不过是把日期天数的推导改下就可以了。