资讯专栏INFORMATION COLUMN

如何实现无限滚动

antz / 2144人阅读

摘要:简介无限滚动对我们来说已经是很常见的功能了,具体表现为当页面滚动到某个位置时就自动加载数据,本文将探讨无限滚动的实现原理以及优化。

简介

无限滚动对我们来说已经是很常见的功能了,具体表现为当页面滚动到某个位置时就自动加载数据,本文将探讨无限滚动的实现原理以及优化。

原理

我们先看看最简单的无限滚动的例子:

function fetchData() {
  fetch(path).then(res => doSomeThing(res.data));
}

window.addEventListener("scroll", fetchData);

上面就是无限滚动最简单的例子啦~
其实就是监听 window 对象的 scroll 事件,然后再触发获取数据的函数~

然而,上面的例子中还有很多问题,其中最大的问题就是 获取数据的函数(以后叫 fetch 函数)没有触发条件, 我们还需要不断优化,才能在生产环境下使用。

添加触发条件

我们先想想,一般情况下,fetch 函数的触发条件有哪些呢 ?

在 fetch 过程中不能重复触发

没有更多数据的时候不能再触发

屏幕距离容器边缘 xxx 的时候触发

前两点很好处理,只要加个 isLoadingisEnd 的变量就可以了。
添加这两个变量之后,我们的代码就变成下面的样子啦:

var isLoading = false;
var isEnd = false;

function fetchData() {

  if ( !isLoading && !isEnd ) {

    isLoading = true;

    fetch(path).then(res => {
      isLoading = false;
      res.data.length === 0 && isEnd = true;
      doSomething(res.data);
    });

  }

}
window.addEventListener("scroll", fetchData);

第三点对不熟悉 DOM 的童鞋来说就有点难度了~

计算屏幕与容器边缘的距离

我们以计算屏幕底部与容器底部边缘为例:

如果有 api 可以直接得到元素底部与屏幕底部的距离就最好啦,可以省去麻烦,但实际上并没有这样的 api。
然而,我们可以通过浏览器提供的两个 api,计算出元素底部与屏幕底部之间的距离。

第一个 api 是 window.innerHeight,它返回的是屏幕(viewport)高度。
第二个 api 就是 Element.getBoundingClientRect ,这个方法用来计算元素边缘与屏幕(viewport)之间的距离。
需要提醒一下,Element.getBoundingClientRect 会得到这么一个类 Object 对象:

ClientRect {
  width: 760,   // 元素宽度
  height: 2500, // 元素高度
  top: -1352,   // 元素上边缘与屏幕上边缘的距离
  bottom: 1239, // 元素下边缘与屏幕上边缘的距离
  left: 760,    // 元素左边缘与屏幕左边缘的距离
  right: 860    // 元素右边缘与屏幕左边缘的距离
}

可以看看下面这图:

     +------> +--------------------------------------------------------+
     |        |                     document.body                      |
     |        |                                                        |
     |        |                                                        |
body.getBoundingClientRect().top                                       |
     |        |                                                        |
     |        |                                                        |
     |        +--------------------------------------------------------+
     |        | browser                                              x |
     +------> +--------------------------------------------------------+ <--+
     |        | window                                                 |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
window.innerHeight                                                     |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                               body.getBoundingClientRect().bottom
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     |        |                                                        |    |
     +------> +--------------------------------------------------------+    |
              |                                                        |    |
              |                                                        |    |
              |                                                        |    |
              |                                                        |    |
              |                                                        |    |
              |                                                        |    |
              +--------------------------------------------------------+ <--+



有了这两个 api,我们很容易就可以计算出元素底部边缘与屏幕底部边缘的位置啦~

我们再修改下我们的代码:

var isLoading = false;
var isEnd = false;
var triggerDistance = 200;

function fetchData() {

  var distance = container.getBoundingClientRect().bottom - window.innerHeight;
  if ( !isLoading && !isEnd && distance < triggerDistance ) {

    isLoading = true;

    fetch(path).then(res => {
      isLoading = false;
      res.data.length === 0 && isEnd = true;
      doSomething(res.data);
    });

  }

}
window.addEventListener("scroll", fetchData);

修改之后,当容器底部与屏幕底部距离小于 200 的时候,才会触发 fetch 函数,这样我们的无限滚动就更加实用啦!

支持 window 以外的元素

然而,并不是只有 window 才可以滚动,拥有高度的级块元素只要设置了 overflow: scroll 都是可以滚动的。
我们需要再修改一下代码来让级块元素也支持无限滚动!

function fetchData() { /* do something */ }
window.addEventListener("scroll", fetchData);
document.getElementById("container").addEventListener("scroll", fetchData);

很简单吧!只需要为该容器元素添加一个 scroll 的事件监听器就好啦!

出处

http://scarletsky.github.io/2016/04/20/how-to-implement-infinite-scroll/

参考资料

https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/79231.html

相关文章

  • Vue下滚动到页面底部无限加载数据Demo

    摘要:下滚动到页面底部无限加载数据看到一篇觉得挺实用的就看了下顺便简单翻译了一下给需要的人参考从这个项目中可以加深对的生命周期的理解何时开始请求如何结合使用原生来写事件等等我这里主要是对原文的重点提取和补充本文技术要点生命周期简单用法格式化日期图 Vue下滚动到页面底部无限加载数据Demo 看到一篇Implementing an Infinite Scroll with Vue.js, 觉得...

    elarity 评论0 收藏0
  • 在React项目中,如何优雅的优化长列表

    摘要:合理的优化长列表,可以提升用户体验。这样保证了无论如何滚动,真实渲染出的节点只有可视区内的列表元素。具体效果如下图所示对于比无优化的情况,优化后的虚拟列表渲染速度提升很明显。是基于来实现的,但是是一个维的列表,而不是网状。   对于较长的列表,比如1000个数组的数据结构,如果想要同时渲染这1000个数据,生成相应的1000个原生dom,我们知道原生的dom元素是很复杂的,如果长列表...

    yearsj 评论0 收藏0
  • 在React项目中,如何优雅的优化长列表

    摘要:合理的优化长列表,可以提升用户体验。这样保证了无论如何滚动,真实渲染出的节点只有可视区内的列表元素。具体效果如下图所示对于比无优化的情况,优化后的虚拟列表渲染速度提升很明显。是基于来实现的,但是是一个维的列表,而不是网状。   对于较长的列表,比如1000个数组的数据结构,如果想要同时渲染这1000个数据,生成相应的1000个原生dom,我们知道原生的dom元素是很复杂的,如果长列表...

    Java_oldboy 评论0 收藏0
  • 【译】无限滚动加载最佳实践

    摘要:优秀无限滚动的五项原则将无限滚动做好,并不是不可能完成的任务。提供为特定项添加书签的可能无限滚动最常见的缺点之一就是,内容出现的时候,没法添加书签。结论无限滚动实现得好的话,可以达到令人难以置信的光滑无缝体验。 本文转载自:众成翻译译者:文蔺链接:http://www.zcfy.cc/article/673原文:https://uxplanet.org/infinite-scrolli...

    Sunxb 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<