思路:用一个容器包裹三个用于显示每个月日历的div,当滚动条滚动到顶部时,设置scrollTop 等于第一个div的
offsetHeight。当滚动条滚动到底部时,设置scrollTop: e.target.scrollTop =
e.target.scrollHeight - e.target.clientHeight -
nextmonth.offsetHeight。以此达到无限滑动的效果
效果图:




<template> <div id="calendar"> <div class="date-title" > <div>日</div>
<div>一</div> <div>二</div> <div>三</div> <div>四</div> <div>五</div> <div>六</div>
</div> <div class="calendar-container" :style="{height:
`${calendarContainerHeight}`}" v-on:scroll="scrollDebounce"> <div
class="date-container premonth"> <div class="date-header">{{
`${preDivCalendar.year}年${preDivCalendar.month + 1}月` }}</div> <div
class="date-board"> <div v-for="i in new Date(preDivCalendar.year,
preDivCalendar.month, 1).getDay()" :key="-i"></div> <div class="date-block"
:class="{todayBlock: i === 1}" v-for="i in
getMonthDayByMonthYear(preDivCalendar.month, preDivCalendar.year)" :key="i">
<span>{{ i }}</span> </div> </div> </div> <div class="date-container
middlemonth"> <div class="date-header">{{
`${middleDivCalendar.year}年${middleDivCalendar.month + 1}月` }}</div> <div
class="date-board"> <div v-for="i in new Date(middleDivCalendar.year,
middleDivCalendar.month, 1).getDay()" :key="-i"></div> <div class="date-block"
:class="{todayBlock: i === 1}" v-for="i in getMonthDayByMonthYear
(middleDivCalendar.month, middleDivCalendar.year)" :key="i"> <span>{{ i
}}</span> </div> </div> </div> <div class="date-container nextmonth"> <div
class="date-header">{{
`${nextMiddleDivCalendar.year}年${nextMiddleDivCalendar.month + 1}月` }}</div>
<div class="date-board"> <div v-for="i in new Date(nextMiddleDivCalendar.year,
nextMiddleDivCalendar.month, 1).getDay()" :key="-i"></div> <div
class="date-block" :class="{todayBlock: i === 1}" v-for="i in
getMonthDayByMonthYear (nextMiddleDivCalendar.month,
nextMiddleDivCalendar.year)" :key="i"> <span>{{ i }}</span> </div> </div>
</div> </div> <div class="fold-btn" @click="isShow=!isShow"> {{ isShow ? '收起' :
'展开' }} <span :class="{topArrow: isShow, bottomArrow: !isShow}"></span> </div>
</div> </template> <script> export default { data () { return { isShow: false,
// 控制日历的收起与展开 calendarContainerHeight: '0', // 日历的高度 scrollTimer: null, //
滚动定时器,用于滚动事件防抖动 preDivCalendar: {year: 2018, month: 6}, // 第一个div显示的日历
middleDivCalendar: {year: 2018, month: 7}, // 中间div显示的日历 nextMiddleDivCalendar:
{year: 2018, month: 8}, // 最后一个div显示的日历 } }, mounted () {
this.middleDivCalendar = {year: new Date().getFullYear(), month: new
Date().getMonth()} // 当日历收起的时候,日历高度刚好只够显示一行日期 this.calendarContainerHeight =
document.querySelector('.date-block').getBoundingClientRect().height + 'px'
this.$nextTick(function () { // DOM更新完成后 const today =
document.querySelector('.todayBlock') today.scrollIntoView() }) }, watch: {
isShow(){ // 监听日历的收起与展开,改变日历的高度 const height =
document.querySelector('.date-block').getBoundingClientRect().height + 'px'
this.calendarContainerHeight = this.isShow ? '3rem' : height if (!this.isShow){
const today = document.querySelector('.todayBlock') today.scrollIntoView() } },
middleDivCalendar () { // 监听中间div日历的时间,根据中间div的日历获取上下div的日历 this.preDivCalendar
= this.getPrevMonth(this.middleDivCalendar.month, this.middleDivCalendar.year)
this.nextMiddleDivCalendar = this.getNextMonth(this.middleDivCalendar.month,
this.middleDivCalendar.year) } }, methods: { getPrevMonth: function (m, y) { //
获取上一个月 let month = m || 11 let year = y year -= m === 0 month -= m !== 0 return
{ year, month } }, getNextMonth: function (m, y) { // 获取下一个月 let month = m let
year = y year += m === 11 month = (1 + month) % 12 return { year, month } },
getMonthDayByMonthYear (month, year) { // 获取某年某月的天数 // 判断是否为闰年 const isLeap =
(year % 100 === 0) ? (year % 400 === 0 ? 1 : 0) : (year % 4 === 0) ? 1 : 0
const monthDay = [31, 28 + isLeap, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] //
数组中的每一项代表每个月的天数 return monthDay[month] }, scrollDebounce (e) {
clearTimeout(this.scrollTimer) let self = this // 设置定时器,防止scroll抖动
this.scrollTimer = setTimeout(function() { if (e.target.scrollTop === 0) {
self.middleDivCalendar = self.getPrevMonth(self.middleDivCalendar.month,
self.middleDivCalendar.year) self.$nextTick(function () { // DOM 更新了 const
premonth = document.querySelector('.premonth') e.target.scrollTop =
premonth.offsetHeight }) } if (e.target.scrollTop + e.target.clientHeight + 1
>= e.target.scrollHeight){ self.middleDivCalendar =
self.getNextMonth(self.middleDivCalendar.month, self.middleDivCalendar.year)
self.$nextTick(function () { // DOM 更新了 const nextmonth =
document.querySelector('.nextmonth') e.target.scrollTop = e.target.scrollHeight
- e.target.clientHeight - nextmonth.offsetHeight }) } }, 100) }, }, } </script>
<style lang="less" scoped> .date-title { display: flex; padding: .10rem 0;
text-align: center; border-bottom: .01rem solid #d1d1d1; div { flex: 1; } }
.calendar-container{ overflow-y: scroll; overflow-scrolling: touch; transition:
height 0.5s ease; .date-container { .date-header { text-align: center; padding:
.07rem 0; background-color: #F8F8F8; } .date-board { display: flex; display:
-webkit-flex; flex-wrap: wrap; -webkit-flex-wrap: wrap; text-align: center; div
{ width: 14.28571%; padding: .10rem 0; } .todayBlock { span { color: red; } } }
} } .fold-btn { display: flex; align-items: center; justify-content: center;
padding: .10rem; color: #0893FF; border-bottom: .01rem solid #d1d1d1; .topArrow
{ font-size: 0; line-height: 0; margin-left: .10rem; border: .05rem solid;
border-color: transparent transparent #0893FF transparent; } .bottomArrow {
font-size: 0; line-height: 0; margin-left: .10rem; border: .05rem solid;
border-color: #0893FF transparent transparent transparent; } } </style>
 

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信