NIKO'S BLOG

简单记录上拉加载更多实现思路

下拉刷新、上拉加载更多是移动端常见的交互效果,也有很多封装好的库供我们方便的调用。但是如果只是一个简单的临时页面,也许不用第三方库手写实现会是一个不错的选择。今天就来简单说说上拉加载更多的实现思路。

分析

把上拉加载更多这个过程拆解一下,可以分成这几个步骤:

  • 页面向下滚动…
  • 页面滚动到了底部
  • 此时,显示加载动画,并发送ajax请求
  • 在请求成功后,隐藏加载动画,填充数据

通过以上步骤,不难发现,这个过程最关键的一步就是判断是否滚动到底部了。要完成这个判断,需要先来了解一下三个长度单位的概念:

  • 文档高度:即整个网页内容的实际高度,这部分高度可能会有一部分是现在看不到,需要滚动一下滚动条才能看到的。
  • 视口高度:即你能在浏览器里看到的网页内容的区域的高度。调整浏览器窗口的高度这个值会随之变化。
  • 滚动条位置:准确来讲是窗口垂直滚动条距离顶端的距离。

如果滚动条滚动到了底部,它们之间满足这个公式:文档高度 - 视口高度 - 滚动条位置 == 0。为了方便DOM操作,省去繁琐的兼容处理。使用jQuery来表示:$(document).height() - $(window).height() - $(window).scrollTop() == 0

踩坑

搞清楚了关键的一步,似乎挺简单的,是时候用代码来实现上面的过程了:

1
2
3
4
5
6
7
8
9
<div class="list">
<ul>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
...
<ul>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
$(function(){
var $list = $('.list');
var htmlNodes = '';
$(window).scroll(function(){
// 为了体验更好,在滚动到顶部之前50px(这个值也可以是其他的,按需求来)的位置时执行关键操作
if($(document).height() - $(window).height() - $(window).scrollTop() > 50){
$list.append('<div class="loading">加载中...</div>')
// 用定时器模拟ajax请求的异步操作
setTimeout(function(){
$('.loading').remove();
for(var i = 0; i < 10; i++){
htmlNodes += '<li>这是一条新闻</li>';
}
$list.html(htmlNodes);
}, 1000);
}
});
});

以上的demo用定时器模拟了ajax请求获取数据的操作,似乎没有什么问题,但是实际运行的时候,滚动到底部的时候,会看到在列表底部追加了多个加载中...节点。这说明if语句块执行了多次,这是因为$(winow).scroll()是以一个很高频率被触发的,比如说滚动滚轮的时候,一秒钟内可能执行了多次$(winow).scroll()。要解决这个问题,需要添加一个全局标识isEnd = false;在滚动到底部时isEnd = true;,然后在请求完成,新的数据渲染完毕时再isEnd = false;,并且在上面的if语句块之前进行这个标识的判断if isEnd return;

升级

踩了一遍坑之后,把上面的代码升级一下(另外把加载中的添加移除节点改为显示和隐藏)。

1
2
3
4
5
6
7
8
9
10
<div class="list">
<ul>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
<li>这是一条新闻</li>
...
<ul>
<div class="loading" style="display:none;">加载中...</div>
</div>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
$(function(){
var $list = $('.list');
var $loading = $('.loading');
var htmlNodes = '';
var isEnd = false;
var page = 0;
$(window).scroll(function(){
if(isEnd) {
return;
}
if($(document).height() - $(window).height() - $(window).scrollTop() > 50){
$.ajax({
type: 'POST',
url: 'somePostUrl',
data: {
page: page++
},
dataType: 'json',
success: function(res){
// render the list
},
beforeSend: function(){
$loading.show();
},
complete: function(){
$loading.hide();
}
});
}
});
});

当然了,这只是一个简单的实现思路,还有很多需要优化的地方,比如移动端的滚动问题…

结语

上面的内容很基础,但也是自己学习的一个总结吧,有错误的地方还望指正。最近比较浮,面对更新迭代如此迅速的前端,感觉有点无所适从。听说vue3都快要到来了,而我却还没有用vue写过一个完整的项目。ES都到ES7,ES8了,而我还在用ES5。焦虑只会让事情变得更糟,所以有一句话希望与和我一样的小白共勉:不要停下来,但要记住:慢下来,才最快。

笔者注

博客内文章若不另外注明,均为原创。转载请注明出处,谢谢。

博客内容主要是对新知识的归纳、总结。记录博客的目的也是为了方便自己日后的巩固复习。欢迎大家提出文章中理解错误的地方,不胜感激。若文章对你有帮助,将是我的荣幸。