如何實現無限滾動

簡介

無限滾動對咱們來講已是很常見的功能了,具體表現爲當頁面滾動到某個位置時就自動加載數據,本文將探討無限滾動的實現原理以及優化。git

原理

咱們先看看最簡單的無限滾動的例子:github

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

window.addEventListener('scroll', fetchData);

上面就是無限滾動最簡單的例子啦~
其實就是監聽 window 對象的 scroll 事件,而後再觸發獲取數據的函數~api

然而,上面的例子中還有不少問題,其中最大的問題就是 獲取數據的函數(之後叫 fetch 函數)沒有觸發條件, 咱們還須要不斷優化,才能在生產環境下使用。瀏覽器

添加觸發條件

咱們先想一想,通常狀況下,fetch 函數的觸發條件有哪些呢 ?函數

  • 在 fetch 過程當中不能重複觸發fetch

  • 沒有更多數據的時候不能再觸發優化

  • 屏幕距離容器邊緣 xxx 的時候觸發code

前兩點很好處理,只要加個 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

相關文章
相關標籤/搜索