注:有缺陷,没有进行scroll事件的防抖、节流处理

前篇讲了一个简单的下拉刷新的实现,当然下拉刷新和页面滚动到底部时,再上拉加载更多的功能是配合着用的,这篇就讲上拉加载更多

先看效果:

  1. 判断scroll到了top,此时手势再下拉则进行刷新
  2. 然后当滚动到底部时,此时发出ajax,添加数据,无限加载
  3. 请求是异步的,这段时间内用户的上拉被忽略

判断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事件优化

如何不择手段提升scroll事件的性能

但这次只是监听了touchstarttouchendtouchmove事件...

标签: none

添加新评论