根据项目需求自己封装的calendar组件
<template> <div class="calendar-wrapper"> <div class="header transition" v-if="HeaderBar"> <div class="pre" @click="changeMonth('pre')"> <image src="/static/img/icons/icon-arrow-left.png" /> </div> <div>{{ y + '年' + formatNum(m) + '月' }}</div> <div class="next" @click="changeMonth('next')"> <image src="/static/img/icons/icon-arrow-right.png" /> </div> </div> <div class="day"> <div class="week-day" :class="{ 'text-ccc': !HeaderBar }" v-for="(item, index) in weekDay" :key="index"> {{ item }} </div> </div> <div :class="{ hide: !monthOpen }" class="content" :style="{ height: height }"> <div class="days transition" :style="{ top: positionTop + 'rpx' }"> <div class="item" :class="{ week: Open && hasWeek(item), weekStart: isWeekStart(item), weekEnd: isWeekEnd(item) }" v-for="(item, index) in dates" :key="index" > <div class="day" :class="{ choose: choose == `${item.year}-${item.month}-${item.date}` && item.isCurM, nolm: !item.isCurM, today: isToday(item.year, item.month, item.date) }" @click="item.isCurM && selectOne(item, $event)" > {{ Number(item.date) }} </div> <div class="markDay" v-if="isMarkDay(item.year, item.month, item.date) && item.isCurM"></div> </div> </div> </div> <!-- <image src="/static/img/icons/logo.png" mode="scaleToFill" v-if="collapsible" @click="toggle" class="weektoggle" :class="{ down: monthOpen }"></image> --> </div> </template> <script> import { getWeek } from '@/static/js/getWeek' export default { name: 'calendar', props: { defaultTime: { type: String, default: '' }, // 星期几为第一天(0为星期日) weekstart: { type: Number, default: 1 }, // 标记的日期 markDays: { type: Array, default: () => { return [] } }, //是否展示月份切换按钮 headerBar: { type: Boolean, default: false }, // 是否展开 open: { type: Boolean, default: false }, //是否可收缩 collapsible: { type: Boolean, default: false }, //未来日期是否不可点击 disabledAfter: { type: Boolean, default: false } }, data() { return { HeaderBar: false, Open: false, weektext: ['日', '一', '二', '三', '四', '五', '六'], y: new Date().getFullYear(), // 年 m: new Date().getMonth() + 1, // 月 date: '', dates: [], // 当前月的日期数据 positionTop: 0, monthOpen: true, choose: '', week: '', startDate: '', endDate: '' } }, watch: { headerBar(val) { this.HeaderBar = val }, open(val) { this.Open = val this.toggle() } }, created() { this.date = this.getToday().date this.choose = this.defaultTime ? this.defaultTime : this.date this.HeaderBar = this.open this.Open = this.open this.dates = this.monthDay(this.y, this.m) !this.Open && this.toggle() }, computed: { // 顶部星期栏 weekDay() { return this.weektext.slice(this.weekstart).concat(this.weektext.slice(0, this.weekstart)) }, height() { return (this.dates.length / 7) * 80 + 'rpx' } }, methods: { formatNum(num) { let res = Number(num) return res < 10 ? '0' + res : res }, getToday() { let date = new Date() let y = date.getFullYear() let m = date.getMonth() let d = date.getDate() let day = new Date().getDay() let _day = day ? day : 7 let week = Math.ceil((d + 6 - _day) / 7) this.week = week let weekText = ['日', '一', '二', '三', '四', '五', '六'] let formatWeek = '星期' + weekText[day] let today = { date: y + '-' + this.formatNum(m + 1) + '-' + this.formatNum(d), day: formatWeek } return today }, // 获取当前月份数据 monthDay(y, month) { let dates = [] let m = Number(month) let firstDayOfMonth = new Date(y, m - 1, 1).getDay() || 7 // 当月第一天星期几 let lastDateOfMonth = new Date(y, m, 0).getDate() // 当月最后一天 let lastDayOfLastMonth = new Date(y, m - 2, 0).getDate() // 上一月的最后一天 let weekstart = this.weekstart === 7 ? 0 : this.weekstart let startDay = (() => { // 周初有几天是上个月的 if (firstDayOfMonth == weekstart) { return 0 } else if (firstDayOfMonth > weekstart) { return firstDayOfMonth - weekstart } else { return 7 - weekstart + firstDayOfMonth } })() let endDay = 7 - ((startDay + lastDateOfMonth) % 7) // 结束还有几天是下个月的 for (let i = 1; i <= startDay; i++) { dates.push({ date: this.formatNum(lastDayOfLastMonth - startDay + i), day: weekstart + i - 1 || 7, month: m - 1 >= 0 ? this.formatNum(m - 1) : 12, year: m - 1 >= 0 ? y : y - 1 }) } for (let j = 1; j <= lastDateOfMonth; j++) { dates.push({ date: this.formatNum(j), day: (j - 1 + firstDayOfMonth) % 7 || 7, month: this.formatNum(m), year: y, isCurM: true //是否当前月份 }) } for (let k = 1; k <= endDay; k++) { dates.push({ date: this.formatNum(k), day: (lastDateOfMonth + startDay + weekstart + k - 1) % 7 || 7, month: m + 1 <= 11 ? this.formatNum(m + 1) : 0, year: m + 1 <= 11 ? y : y + 1 }) } return dates }, // isWorkDay(y, m, d) { // //是否工作日 // let ymd = `${y}/${m}/${d}` // let formatDY = new Date(ymd.replace(/-/g, '/')) // let day = formatDY.getDay() // if (day == 0 || day == 6) { // return false // } else { // return true // } // }, hasWeek(i) { const month = this.choose.split('-')[1] if (month === i.month) { let date = parseInt(i.date) let day = i.day let _day = day ? day : 7 let week = Math.ceil((date + 6 - _day) / 7) Math.ceil((date + 6 - _day) / 7) return this.week === week } }, isWeekStart(item) { const time = `${item.year}-${item.month}-${item.date}` return time === getWeek(this.choose).startDate }, isWeekEnd(item) { const time = `${item.year}-${item.month}-${item.date}` return time === getWeek(this.choose).endDate }, isFutureDay(y, m, d) { //是否未来日期 let ymd = `${y}/${m}/${d}` let formatDY = new Date(ymd.replace(/-/g, '/')) let showTime = formatDY.getTime() let curTime = new Date().getTime() if (showTime > curTime) { return true } else { return false } }, // 标记日期 isMarkDay(y, m, d) { let flag = false for (let i = 0; i < this.markDays.length; i++) { let dy = `${y}-${m}-${d}` if (this.markDays[i] == dy) { flag = true break } } return flag }, isToday(y, m, d) { let checkD = y + '-' + m + '-' + d let today = this.date if (checkD == today) { return true } else { return false } }, // 展开收起 toggle() { this.monthOpen = !this.monthOpen if (this.monthOpen) { this.positionTop = 0 } else { let index = -1 this.dates.forEach((i, x) => { this.isToday(i.year, i.month, i.date) && (index = x) }) this.positionTop = -((Math.ceil((index + 1) / 7) || 1) - 1) * 80 } }, // 点击回调 selectOne(i) { let time = `${i.year}-${i.month}-${i.date}` let selectD = new Date(time).getTime() let curTime = new Date().getTime() let day = new Date(time).getDay() let date = new Date(time).getDate() let _day = day ? day : 7 this.week = Math.ceil((date + 6 - _day) / 7) let weekText = ['日', '一', '二', '三', '四', '五', '六'] let formatWeek = '星期' + weekText[day] let response = { date: time, day: formatWeek } if (!i.isCurM) { // console.log('不在当前月范围内'); return false } if (selectD > curTime) { if (this.disabledAfter) { // console.log('未来日期不可选') return false } else { this.choose = time this.$emit('onDayClick', response) } } else { this.choose = time this.$emit('onDayClick', response) } // console.log(response); }, //改变年月 changYearMonth(y, m) { this.dates = this.monthDay(y, m) this.y = y this.m = m }, changeMonth(type) { if (type == 'pre') { if (this.m + 1 == 2) { this.m = 12 this.y = this.y - 1 } else { this.m = this.m - 1 } } else { if (this.m + 1 == 13) { this.m = 1 this.y = this.y + 1 } else { this.m = this.m + 1 } } this.dates = this.monthDay(this.y, this.m) } } } </script> <style lang="scss" scoped> .calendar-wrapper { color: #42464a; font-size: 28rpx; text-align: center; background-color: #fff; padding-bottom: 20rpx; .header { display: flex; align-items: center; justify-content: center; height: 80rpx; color: #42464a; font-size: 32rpx; font-weight: bold; .pre, .next { font-size: 28rpx; font-weight: normal; padding: 8rpx 15rpx; image { width: 6px; height: 10px; } } .pre { margin-right: 30rpx; } .next { margin-left: 30rpx; } } .day { display: flex; align-items: center; height: 70rpx; line-height: 70rpx; border-bottom: 1rpx solid rgba(255, 255, 255, 0.2); .week-day { flex: 1; } } .content { position: relative; overflow: hidden; transition: height 0.4s ease; .days { transition: top 0.3s; display: flex; align-items: center; flex-wrap: wrap; position: relative; .item { position: relative; display: flex; align-items: center; justify-content: center; height: 80rpx; line-height: 80rpx; width: calc(100% / 7); .day { font-style: normal; display: inline-block; width: 50rpx; height: 50rpx; line-height: 50rpx; overflow: hidden; border-radius: 50rpx; &.choose { background-color: #f5f8fb; } &.nolm { color: #666; opacity: 0.3; } } /* .isWorkDay { color: #42464a; } */ .today { /* background-color: #e4e4e4; */ } .markDay { position: absolute; bottom: 5px; width: 8rpx; height: 8rpx; background: #4d7df9; border-radius: 10rpx; font-style: normal; pointer-events: none; } } .week { background-color: #f5f8fb; } .weekStart { border-radius: 20px 0 0 20px; } .weekEnd { border-radius: 0 20px 20px 0; } } } .hide { height: 80rpx !important; } .weektoggle { width: 85rpx; height: 32rpx; position: relative; bottom: -42rpx; &.down { transform: rotate(180deg); bottom: 0; } } } </style>
页面中调用:
<calendar ref="calendar" :defaultTime="defaultTime" :markDays="markDays" :headerBar="isHeaderBar" :open="isOpen" @onDayClick="onDayClick"></calendar>
参考链接:https://github.com/AR1N/uniapp-calendar