原生JS Intersection Observer API實現懶加載
引言
前一陣子在做一個項目的時候,因為每組數據都要先通過很龐大的計算,才把計算後的結果 Render 到頁面上,但這樣就導致如果單頁查出來的數據超過大概 5 筆,就會需要等待一段有感的時間,才能看到結果出現在畫面上。
後來為瞭解決這差勁用戶體驗,就使用到的標題上說到的 Lazy Loading 來處理。簡單說就是,雖然要顯示的數據量有 10 筆,但因為一個頁面大概隻能呈現 2 到 3 筆,那我就先計算那 2 到 3 筆數據然後顯示就好,剩下的數據等使用者往下滾再繼續顯示,這樣等待時間就不會太久。
然後身為一個前端工程師,再想到這個解法以後,當然就是上 Github 找一個簡單又方便的組件來解決它 😂,而最後找到的 vue-scroll-loader 使用起來非常容易,代碼也少少的,所以就在處理完 issue 後,看它內部是如何實現 Lazy Loading,於是就看到今天主要講的 Intersection Observer API 啦!
Intersection Observer API
那 Intersection Observer API 到底是什麼?為什麼它可以用來實現 Lazy Loading 呢?以 MDN 的說法來說:
Intersection Observer API 提供瞭一種異步檢測目標元素與祖先元素或 viewport 相交情況變化的方法。
簡單說的意思就是隻要使用 Intersection Observer API,就能夠監聽目標的元素在畫面上出現或離開的時候,執行你交給它的 callback 方法。下方就來看看使用的方式吧!
使用方法
首先要有簡單的 HTML 和 CSS,主要目標就是把 div 放在往下滾才會出現的地方:
body { height: 1000px; } .box { width: 100px; height: 100px; background: #000; position: absolute; top: 500px; }
<body> <div class="box"></div> </body>
接著我們用 Intersection Observer API 的 observe
方法,把要監聽的 div
當作參數傳給它,並用 callback
讓它可以在 div 出現和離開的時候給個消息:
const intersectionObserver = new IntersectionObserver( () => { console.log('hi'); } ); intersectionObserver.observe( document.querySelector('.box') );
執行的結果就會像這樣子:
而 Intersection Observer API 在執行 callback
的時候,也會給你一個 Array
,Array
是所有正在監聽的元素,我們可以從這些元素裡的 isIntersecting
來判斷當前的元素是出現在畫面中,還是離開畫面瞭:
const intersectionObserver = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { console.log('我進來瞭!'); } else { console.log('我又出去瞭!'); } } ); intersectionObserver.observe( document.querySelector('.box') );
執行結果:
最後就是當你不再需要繼續監聽元素的時候,可以使用 unobserve
來解除監聽,使用時就像監聽用的 observe
一樣,給它不需要再監聽的元素:
intersectionObserver.unobserve( document.querySelector('.box') );
以上就是 Intersection Observer API 的基本用法,當然還有其他比較仔細的設置(可以看 MDN 的介紹),但如果要完成一個簡單的 Lazy Loading,那隻要會上方的幾種使用方式就綽綽有馀瞭!
Lazy Loading
Intersection Observer API 實現 Lazy Loading 的方法就是在數據列表的最後放個 loading
的小動畫,接著隻要去監聽小動畫,當它出現在頁面中的時候,用 Intersection Observer API 的 callback
載入更多數據。
首先一樣先簡單寫個要顯示數據的 <ul>
,和要監聽的元素,這裡我就不做小動畫瞭,直接用 Loading…
文字代替 😂:
<body> <ul class="list"></ul> <div class="loading">Loading...</div> </body>
要註意監聽的元素必須要在載入數據的最下面哦!不然它不會被監聽到“出現在頁面上”瞭(這個下方會更詳細說明註意事項)。
JavaScript 的部分先貼代碼,下方再來解釋:
const data = Array.from(Array(200)).map( (_value, index) => `第 ${index + 1} 筆資料` ); const render = () => { const list = document.querySelector('.list'); const LOAD_DATA_COUNT = 50; const startLoadIndex = list.childNodes.length; const endLoadIndex = startLoadIndex + LOAD_DATA_COUNT; for (let i = startLoadIndex; i < endLoadIndex; i++) { if (data[i]) { const text = document.createTextNode(data[i]); const li = document.createElement('li'); li.appendChild(text); list.appendChild(li); } } if (endLoadIndex >= data.length) { const loading = document.querySelector('.loading'); loading.style.display = 'none'; intersectionObserver.unobserve(loading); } }; render(); const intersectionObserver = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { setTimeout(render, 1000); } } ); intersectionObserver.observe( document.querySelector('.loading') );
- 先用循環產生 200 筆的假數據
- 寫一個
render
的方法,把還沒載入的數據循環加去,這裡一次加 50 筆數據 - 在
render
內加完數據,去判斷當前加到的index
有沒有大於數據總數,如果有的話代表所有數據顯示完瞭,因此隱藏loading
,並移除 Intersection Observer API 對loading
的監聽 - 畢竟一開始畫面上還是要有數據!所以先手動執行第一次
render
方法 - 用 Intersection Observer API 監聽
loading
,隻要一出現在畫面上(代表使用者看完目前的數據,就要在執行render
。這裡為瞭有真正render
的感覺,我用setTimeout
來延遲1
秒
執行的效果就會像這樣子:
但是還有一點要註意的地方,以上方的例子來說,如果 Intersection Observer API 因為 loading
出現在頁面中執行瞭 render,但是 render 後的數據量卻不足以把 loading
移到畫面外,那 loading
就會一直停留在畫面中,而不是“出現在畫面中”,這麼一來,Intersection Observer API 也就不會觸發 render
載入更多數據。
最後來看一下支持情況。ntersection Observe API 的支持度算不錯瞭,但如果產品有要考慮到 IE 的客戶群就沒辦法用瞭。 😅
最後還是覺得從開源項目裡面以學到很多有趣的東西,也推薦大傢可以在使用某些組件時候偷看一下背後的源碼怎麼處理的。 😂
~完,我是刷碗智,新的一年,我們一起洗刷刷新!!
代碼部署後可能存在的BUG沒法實時知道,事後為瞭解決這些BUG,花瞭大量的時間進行log 調試,這邊順便給大傢推薦一個好用的BUG監控工具 Fundebug。
原文:https://medium.com/starbugs/%…
以上就是原生JS Intersection Observer API實現懶加載的詳細內容,更多關於JS Intersection Observer API懶加載的資料請關註WalkonNet其它相關文章!
推薦閱讀:
- 可視化埋點平臺元素曝光采集intersectionObserver思路實踐
- 利用原生JS實現懶加載lazyLoad的三種方法總結
- ResizeObserver API使用示例詳解
- Vue項目首屏性能優化組件實戰指南
- ResizeObserver 監視 DOM大小變化示例詳解