<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          社區(qū)精選 | 用原生的 JavaScript Intersection Observer API 實(shí)現(xiàn) Lazy Loading

          共 6066字,需瀏覽 13分鐘

           ·

          2022-07-27 03:47

          今天為各位帶來(lái)的是社區(qū)作者 前端小智 的文章,在這篇文章中他為大家介紹了 Intersection Observer API。


          讓我們一起來(lái)了解吧~



          前一陣子在做一個(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)在畫(huà)面上。


          后來(lái)為了解決這差勁用戶(hù)體驗(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)的元素在畫(huà)面上出現(xiàn)或離開(kāi)的時(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)和離開(kāi)的時(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)在畫(huà)面中,還是離開(kāi)畫(huà)面了:


          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ì)上方的幾種使用方式就綽綽有馀了!

          地址:

          https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API#creating_an_intersection_observer


          Lazy Loading


          Intersection Observer API 實(shí)現(xiàn) Lazy Loading 的方法就是在數(shù)據(jù)列表的最后放個(gè) loading 的小動(dòng)畫(huà),接著只要去監(jiān)聽(tīng)小動(dòng)畫(huà),當(dāng)它出現(xiàn)在頁(yè)面中的時(shí)候,用 Intersection Observer API 的 callback 載入更多數(shù)據(jù)。


          首先一樣先簡(jiǎn)單寫(xiě)個(gè)要顯示數(shù)據(jù)的 <ul>,和要監(jiān)聽(tīng)的元素,這裡我就不做小動(dòng)畫(huà)了,直接用 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)解釋?zhuān)?/span>


          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')
          );

          1. 先用循環(huán)產(chǎn)生 200 筆的假數(shù)據(jù)

          2. 寫(xiě)一個(gè) render 的方法,把還沒(méi)載入的數(shù)據(jù)循環(huán)加去,這里一次加 50 筆數(shù)據(jù)

          3.  render 內(nèi)加完數(shù)據(jù),去判斷當(dāng)前加到的 index 有沒(méi)有大于數(shù)據(jù)總數(shù),如果有的話(huà)代表所有數(shù)據(jù)顯示完了,因此隱藏 loading,并移除 Intersection Observer API 對(duì) loading 的監(jiān)聽(tīng)

          4. 畢竟一開(kāi)始畫(huà)面上還是要有數(shù)據(jù)!所以先手動(dòng)執(zhí)行第一次 render 方法

          5. 用 Intersection Observer API 監(jiān)聽(tīng) loading,只要一出現(xiàn)在畫(huà)面上(代表使用者看完目前的數(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 移到畫(huà)面外,那 loading 就會(huì)一直停留在畫(huà)面中,而不是“出現(xiàn)在畫(huà)面中”,這麼一來(lái),Intersection Observer API 也就不會(huì)觸發(fā) render 載入更多數(shù)據(jù)。

          最后來(lái)看一下支持情況。ntersection Observe API 的支持度算不錯(cuò)了,但如果產(chǎn)品有要考慮到 IE 的客戶(hù)群就沒(méi)辦法用了。??


          最后還是覺(jué)得從開(kāi)源項(xiàng)目里面以學(xué)到很多有趣的東西,也推薦大家可以在使用某些組件時(shí)候偷看一下背后的源碼怎麼處理的。??



          SegmentFault 思否社區(qū)小編說(shuō)


          自 2022-07-01 起 SegmentFault 思否公眾號(hào)改版啦!之后將陸續(xù)推出新的欄目和大家見(jiàn)面?。ㄕ?qǐng)拭目以待呀~?


          在「社區(qū)精選」欄目中,我們將為廣大開(kāi)發(fā)者推薦來(lái)自 SegmentFault 思否開(kāi)發(fā)者社區(qū)的優(yōu)質(zhì)技術(shù)文章,這些文章全部出自社區(qū)中充滿(mǎn)智慧的技術(shù)創(chuàng)作者哦!


          希望通過(guò)這一欄目,大家可以共同學(xué)習(xí)技術(shù)干貨,GET 新技能和各種花式技術(shù)小 Tips。


          歡迎越來(lái)越多的開(kāi)發(fā)者加入創(chuàng)作者的行列,我們將持續(xù)甄選出社區(qū)中優(yōu)質(zhì)的內(nèi)容推介給更多人,讓閃閃發(fā)光的技術(shù)創(chuàng)作者們走到聚光燈下,被更多人認(rèn)識(shí)。


          「社區(qū)精選」投稿郵箱:[email protected]

          投稿請(qǐng)附上社區(qū)文章地址




          點(diǎn)擊左下角閱讀原文,到 SegmentFault 思否社區(qū) 和文章作者展開(kāi)更多互動(dòng)和交流,公眾號(hào)后臺(tái)回復(fù)“ 入群 ”即可加入我們的技術(shù)交流群,收獲更多的技術(shù)文章~

          - END -

          瀏覽 42
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  天堂新版8中文在线8 | 日韩无码A级 | 国产盗摄成人一区二区 | 手机无码在线观看 | 丁香五月婷婷视频在线入口 |