Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

简易的上拉加载更多 #12

Open
xixigiggling opened this issue Jul 26, 2018 · 0 comments
Open

简易的上拉加载更多 #12

xixigiggling opened this issue Jul 26, 2018 · 0 comments

Comments

@xixigiggling
Copy link
Owner

xixigiggling commented Jul 26, 2018

注:有重大缺陷,没有进行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事件...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant