摘要:簡介無限滾動對我們來說已經是很常見的功能了,具體表現為當頁面滾動到某個位置時就自動加載數據,本文將探討無限滾動的實現原理以及優化。
簡介
無限滾動對我們來說已經是很常見的功能了,具體表現為當頁面滾動到某個位置時就自動加載數據,本文將探討無限滾動的實現原理以及優化。
原理我們先看看最簡單的無限滾動的例子:
function fetchData() { fetch(path).then(res => doSomeThing(res.data)); } window.addEventListener("scroll", fetchData);
上面就是無限滾動最簡單的例子啦~
其實就是監聽 window 對象的 scroll 事件,然后再觸發獲取數據的函數~
然而,上面的例子中還有很多問題,其中最大的問題就是 獲取數據的函數(以后叫 fetch 函數)沒有觸發條件, 我們還需要不斷優化,才能在生產環境下使用。
添加觸發條件我們先想想,一般情況下,fetch 函數的觸發條件有哪些呢 ?
在 fetch 過程中不能重復觸發
沒有更多數據的時候不能再觸發
屏幕距離容器邊緣 xxx 的時候觸發
前兩點很好處理,只要加個 isLoading 和 isEnd 的變量就可以了。
添加這兩個變量之后,我們的代碼就變成下面的樣子啦:
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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/79231.html
摘要:下滾動到頁面底部無限加載數據看到一篇覺得挺實用的就看了下順便簡單翻譯了一下給需要的人參考從這個項目中可以加深對的生命周期的理解何時開始請求如何結合使用原生來寫事件等等我這里主要是對原文的重點提取和補充本文技術要點生命周期簡單用法格式化日期圖 Vue下滾動到頁面底部無限加載數據Demo 看到一篇Implementing an Infinite Scroll with Vue.js, 覺得...
摘要:合理的優化長列表,可以提升用戶體驗。這樣保證了無論如何滾動,真實渲染出的節點只有可視區內的列表元素。具體效果如下圖所示對于比無優化的情況,優化后的虛擬列表渲染速度提升很明顯。是基于來實現的,但是是一個維的列表,而不是網狀。 ??對于較長的列表,比如1000個數組的數據結構,如果想要同時渲染這1000個數據,生成相應的1000個原生dom,我們知道原生的dom元素是很復雜的,如果長列表...
摘要:合理的優化長列表,可以提升用戶體驗。這樣保證了無論如何滾動,真實渲染出的節點只有可視區內的列表元素。具體效果如下圖所示對于比無優化的情況,優化后的虛擬列表渲染速度提升很明顯。是基于來實現的,但是是一個維的列表,而不是網狀。 ??對于較長的列表,比如1000個數組的數據結構,如果想要同時渲染這1000個數據,生成相應的1000個原生dom,我們知道原生的dom元素是很復雜的,如果長列表...
摘要:優秀無限滾動的五項原則將無限滾動做好,并不是不可能完成的任務。提供為特定項添加書簽的可能無限滾動最常見的缺點之一就是,內容出現的時候,沒法添加書簽。結論無限滾動實現得好的話,可以達到令人難以置信的光滑無縫體驗。 本文轉載自:眾成翻譯譯者:文藺鏈接:http://www.zcfy.cc/article/673原文:https://uxplanet.org/infinite-scrolli...
閱讀 2491·2021-11-24 09:39
閱讀 3415·2021-11-15 11:37
閱讀 2268·2021-10-08 10:04
閱讀 3977·2021-09-09 11:54
閱讀 1890·2021-08-18 10:24
閱讀 1060·2019-08-30 11:02
閱讀 1805·2019-08-29 18:45
閱讀 1661·2019-08-29 16:33