简易的上拉加载更多
注:有缺陷,没有进行scroll事件的防抖、节流处理
前篇讲了一个简单的下拉刷新的实现,当然下拉刷新和页面滚动到底部时,再上拉加载更多的功能是配合着用的,这篇就讲上拉加载更多
先看效果:
- 判断scroll到了top,此时手势再下拉则进行刷新
- 然后当滚动到底部时,此时发出ajax,添加数据,无限加载
- 请求是异步的,这段时间内用户的上拉被忽略
判断scroll到顶部/底部
<div class="latest_test" v-show="!isVideoShow" ref="wrapper">
<videoBlock v-for="(item, index) in videolist" :key="index" :videoInfo="item" @deliverItem="jump(item)"></videoBlock>
</div>
判断的方法是 this.$refs.wrapper.scrollTop === 0
而底部的判断会稍微麻烦一点,首先有这几个概念的梳理:
Js中ScrollTop、ScrollHeight、ClientHeight、OffsetHeight等整理
搞清clientHeight、offsetHeight、scrollHeight、offsetTop、scrollTop
clientHeight, scrollHeight, scrollTop以及滚动无限加载的实现
简而言之:
什么是滚动? 当本元素的子元素比本元素高且overflow=scroll
时(auto是由浏览器来决定),本元素会scroll
clientHeight
:元素的高度,包括padding
但不包括border
、水平滚动条、margin
scrollTop
:滚动条向下滚动的距离或者说元素距离他容器顶部的像素距离scrollHeight
:整个的高度,滚动不可见的部分也是
于是判断的方法就是:
let topHeight = this.$refs.wrapper.scrollTop,
selfHeight = this.$refs.wrapper.clientHeight,
totalHeigt = this.$refs.wrapper.scrollHeight,
diff = topHeight + selfHeight - totalHeigt;
// 实际上要给予一定的误差范围,因为有时用户一下可以滚动很远,而且可能出现上拉成负数
if(diff < 300 && diff >= -10) { }
请求时,处理请求分页
这次比较简单,后端数据是一页20条,
{
page: 1,
limit: 20
}
也就是分两种情况,刷新时直接就请求page:1
,然后this.videolist = data;
,而加载更多的时候,则需要
this.videolist = this.videolist.concat(
data
);
但是这里的page
需要另外处理一下, page === Math.round(this.videolist.length / 20) + 1
,这样就可以实现自动page自动增长了
防止用户多次上拉加载
一开始会遇到一个这样的问题,当用户下滑到底部的时候,此时发出请求,当异步数据还没加载的时候,用户再次下滑的时候,又发出了请求!,这样就很尴尬了...
解决的方法是加一个isPending
来控制
在监听touchend
事件时,
// direction:1就是上拉,当下拉而且异步请求数据已成功的情况下执行
else if (direction === 1 && !this.isPending) {
// code here...
}
隐藏的彩蛋,promise让代码更清晰
一开始,当滚动到页面底部的时候,就发出ajax
// if...滚动到底部
let myData = {
data: {
page: 1,
limit: 20
}
};
let count = Math.round(this.videolist.length / 20) + 1;
myData.data.page = count;
this.$http
.post('XXXXXXX', myData)
.then(response => {
if (response.data.code === 200) {
this.videolist = this.videolist.concat(
response.data.data.list
);
} else {
Toast('error');
}
});
以上的代码是,揉杂在监听的touchend
事件回调里面的,不仅刷新部分也要写上这样一段几乎类似的代码,导致代码很长,于是就把请求抽离出来,通过返回promise的方式,发现这样之后代码清晰很多...
// 抽离出来的请求函数
loadMore() {
return new Promise((resolve, reject) => {
let myData = {
data: {
page: 1,
limit: 20
}
};
let count = Math.round(this.videolist.length / 20) + 1;
myData.data.page = count;
this.$http
.post('XXXXXXX', myData)
.then(response => {
if (response.data.code === 200) {
resolve(response.data.data.list);
} else {
reject();
}
});
});
},
// 请求函数的使用
this.loadMore()
.then((data) => {
this.videolist = this.videolist.concat(
data
);
this.isPending = false;
})
.catch(()=>{
Toast('获取视频列表失败,请稍后..');
});
隐藏的彩蛋,scroll事件优化
但这次只是监听了touchstart
、touchend
、touchmove
事件...