原生JS?Intersection?Observer?API實(shí)現(xiàn)懶加載
引言
前一陣子在做一個(gè)項(xiàng)目的時(shí)候,因?yàn)槊拷M數(shù)據(jù)都要先通過(guò)很龐大的計(jì)算,才把計(jì)算后的結(jié)果 Render 到頁(yè)面上,但這樣就導(dǎo)致如果單頁(yè)查出來(lái)的數(shù)據(jù)超過(guò)大概 5 筆,就會(huì)需要等待一段有感的時(shí)間,才能看到結(jié)果出現(xiàn)在畫面上。
后來(lái)為了解決這差勁用戶體驗(yàn),就使用到的標(biāo)題上說(shuō)到的 Lazy Loading 來(lái)處理。簡(jiǎn)單說(shuō)就是,雖然要顯示的數(shù)據(jù)量有 10 筆,但因?yàn)橐粋€(gè)頁(yè)面大概只能呈現(xiàn) 2 到 3 筆,那我就先計(jì)算那 2 到 3 筆數(shù)據(jù)然后顯示就好,剩下的數(shù)據(jù)等使用者往下滾再繼續(xù)顯示,這樣等待時(shí)間就不會(huì)太久。
然后身為一個(gè)前端工程師,再想到這個(gè)解法以后,當(dāng)然就是上 Github 找一個(gè)簡(jiǎn)單又方便的組件來(lái)解決它 ??,而最后找到的 vue-scroll-loader 使用起來(lái)非常容易,代碼也少少的,所以就在處理完 issue 后,看它內(nèi)部是如何實(shí)現(xiàn) Lazy Loading,于是就看到今天主要講的 Intersection Observer API 啦!
Intersection Observer API
那 Intersection Observer API 到底是什麼?為什麼它可以用來(lái)實(shí)現(xiàn) Lazy Loading 呢?以 MDN 的說(shuō)法來(lái)說(shuō):
Intersection Observer API 提供了一種異步檢測(cè)目標(biāo)元素與祖先元素或 viewport 相交情況變化的方法。
簡(jiǎn)單說(shuō)的意思就是只要使用 Intersection Observer API,就能夠監(jiān)聽(tīng)目標(biāo)的元素在畫面上出現(xiàn)或離開的時(shí)候,執(zhí)行你交給它的 callback 方法。下方就來(lái)看看使用的方式吧!
使用方法
首先要有簡(jiǎn)單的 HTML 和 CSS,主要目標(biāo)就是把 div 放在往下滾才會(huì)出現(xiàn)的地方:
body { height: 1000px; } .box { width: 100px; height: 100px; background: #000; position: absolute; top: 500px; }
<body> <div class="box"></div> </body>
接著我們用 Intersection Observer API 的 observe
方法,把要監(jiān)聽(tīng)的 div
當(dāng)作參數(shù)傳給它,并用 callback
讓它可以在 div 出現(xiàn)和離開的時(shí)候給個(gè)消息:
const intersectionObserver = new IntersectionObserver( () => { console.log('hi'); } ); intersectionObserver.observe( document.querySelector('.box') );
執(zhí)行的結(jié)果就會(huì)像這樣子:
而 Intersection Observer API 在執(zhí)行 callback
的時(shí)候,也會(huì)給你一個(gè) Array
,Array
是所有正在監(jiān)聽(tīng)的元素,我們可以從這些元素里的 isIntersecting
來(lái)判斷當(dāng)前的元素是出現(xiàn)在畫面中,還是離開畫面了:
const intersectionObserver = new IntersectionObserver( (entries) => { if (entries[0].isIntersecting) { console.log('我進(jìn)來(lái)了!'); } else { console.log('我又出去了!'); } } ); intersectionObserver.observe( document.querySelector('.box') );
執(zhí)行結(jié)果:
最后就是當(dāng)你不再需要繼續(xù)監(jiān)聽(tīng)元素的時(shí)候,可以使用 unobserve
來(lái)解除監(jiān)聽(tīng),使用時(shí)就像監(jiān)聽(tīng)用的 observe
一樣,給它不需要再監(jiān)聽(tīng)的元素:
intersectionObserver.unobserve( document.querySelector('.box') );
以上就是 Intersection Observer API 的基本用法,當(dāng)然還有其他比較仔細(xì)的設(shè)置(可以看 MDN 的介紹),但如果要完成一個(gè)簡(jiǎn)單的 Lazy Loading,那只要會(huì)上方的幾種使用方式就綽綽有馀了!
Lazy Loading
Intersection Observer API 實(shí)現(xiàn) Lazy Loading 的方法就是在數(shù)據(jù)列表的最后放個(gè) loading
的小動(dòng)畫,接著只要去監(jiān)聽(tīng)小動(dòng)畫,當(dāng)它出現(xiàn)在頁(yè)面中的時(shí)候,用 Intersection Observer API 的 callback
載入更多數(shù)據(jù)。
首先一樣先簡(jiǎn)單寫個(gè)要顯示數(shù)據(jù)的 <ul>
,和要監(jiān)聽(tīng)的元素,這裡我就不做小動(dòng)畫了,直接用 Loading…
文字代替 ??:
<body> <ul class="list"></ul> <div class="loading">Loading...</div> </body>
要注意監(jiān)聽(tīng)的元素必須要在載入數(shù)據(jù)的最下面哦!不然它不會(huì)被監(jiān)聽(tīng)到“出現(xiàn)在頁(yè)面上”了(這個(gè)下方會(huì)更詳細(xì)說(shuō)明注意事項(xiàng))。
JavaScript 的部分先貼代碼,下方再來(lái)解釋:
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') );
- 先用循環(huán)產(chǎn)生 200 筆的假數(shù)據(jù)
- 寫一個(gè)
render
的方法,把還沒(méi)載入的數(shù)據(jù)循環(huán)加去,這里一次加 50 筆數(shù)據(jù) - 在
render
內(nèi)加完數(shù)據(jù),去判斷當(dāng)前加到的index
有沒(méi)有大于數(shù)據(jù)總數(shù),如果有的話代表所有數(shù)據(jù)顯示完了,因此隱藏loading
,并移除 Intersection Observer API 對(duì)loading
的監(jiān)聽(tīng) - 畢竟一開始畫面上還是要有數(shù)據(jù)!所以先手動(dòng)執(zhí)行第一次
render
方法 - 用 Intersection Observer API 監(jiān)聽(tīng)
loading
,只要一出現(xiàn)在畫面上(代表使用者看完目前的數(shù)據(jù),就要在執(zhí)行render
。這裡為了有真正render
的感覺(jué),我用setTimeout
來(lái)延遲1
秒
執(zhí)行的效果就會(huì)像這樣子:
但是還有一點(diǎn)要注意的地方,以上方的例子來(lái)說(shuō),如果 Intersection Observer API 因?yàn)?nbsp;loading
出現(xiàn)在頁(yè)面中執(zhí)行了 render,但是 render 后的數(shù)據(jù)量卻不足以把 loading
移到畫面外,那 loading
就會(huì)一直停留在畫面中,而不是“出現(xiàn)在畫面中”,這麼一來(lái),Intersection Observer API 也就不會(huì)觸發(fā) render
載入更多數(shù)據(jù)。
最后來(lái)看一下支持情況。ntersection Observe API 的支持度算不錯(cuò)了,但如果產(chǎn)品有要考慮到 IE 的客戶群就沒(méi)辦法用了。 ??
最后還是覺(jué)得從開源項(xiàng)目里面以學(xué)到很多有趣的東西,也推薦大家可以在使用某些組件時(shí)候偷看一下背后的源碼怎麼處理的。 ??
~完,我是刷碗智,新的一年,我們一起洗刷刷新?。?/p>
代碼部署后可能存在的BUG沒(méi)法實(shí)時(shí)知道,事后為了解決這些BUG,花了大量的時(shí)間進(jìn)行l(wèi)og 調(diào)試,這邊順便給大家推薦一個(gè)好用的BUG監(jiān)控工具 Fundebug。
原文:https://medium.com/starbugs/%...
以上就是原生JS Intersection Observer API實(shí)現(xiàn)懶加載的詳細(xì)內(nèi)容,更多關(guān)于JS Intersection Observer API懶加載的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
vite(vue3)配置內(nèi)網(wǎng)ip訪問(wèn)的方法步驟
Vite是一個(gè)快速的構(gòu)建工具,Vue3是一個(gè)流行的JavaScript框架,下面這篇文章主要給大家介紹了關(guān)于vite(vue3)配置內(nèi)網(wǎng)ip訪問(wèn)的方法步驟,文中通過(guò)圖文介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05vue實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能
這篇文章主要為大家詳細(xì)介紹了vue實(shí)現(xiàn)簡(jiǎn)易計(jì)算器功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法分享
下面小編就為大家分享一篇在vue項(xiàng)目創(chuàng)建的后初始化首次使用stylus安裝方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-01-01