圖片懶加載幾個(gè)版本的實(shí)現(xiàn)對比
大廠技術(shù)??高級前端??Node進(jìn)階
點(diǎn)擊上方?程序員成長指北,關(guān)注公眾號
回復(fù)1,加入高級Node交流群
背景
圖片懶加載是針對圖片加載時(shí)機(jī)的一種優(yōu)化,在一些圖片量比較大的網(wǎng)站(比如電商網(wǎng)站首頁,或者團(tuán)購網(wǎng)站、小游戲首頁等),如果我們嘗試在用戶打開頁面的時(shí)候,就把所有的圖片資源加載完畢,那么很可能會造成白屏、卡頓等現(xiàn)象,因?yàn)閳D片真的太多了,一口氣處理這么多任務(wù),瀏覽器做不到啊!
懶加載是為了讓瀏覽器只加載可視區(qū)內(nèi)的圖片,可視區(qū)外的大量圖片不進(jìn)行加載,當(dāng)頁面滾動(dòng)到后面去的時(shí)候再進(jìn)行加載。這樣做有很多好處可以增加首屏加載的速度,畢竟,用戶點(diǎn)開頁面的瞬間,呈現(xiàn)給他的只是首屏,我們只要把首屏的資源圖片加載處理就可以了,至于下面的圖片,當(dāng)用戶下滑當(dāng)當(dāng)前位置的時(shí)候,在加載出來也是沒問題的,對于性能壓力也小了,用戶體驗(yàn)也沒有變差。
解答
圖片懶加載的原理就是需要知道圖片是否在可視區(qū)內(nèi)了,當(dāng)圖片到達(dá)可視區(qū)內(nèi)就需要去請求對應(yīng)的圖片加載出來
頁面中的img標(biāo)簽一般如下寫
class="lazyload"?src="placeholder.jpg"?src="real_image.jpg"?/>
其中src首先賦值一個(gè)占位的圖片,一般是一個(gè)很小的圖片,進(jìn)行占位,src是實(shí)際需要展示的圖片,原理就是當(dāng)圖片在可視區(qū)內(nèi)的時(shí)候?qū)rc的圖片選渲染出來即可。
1、原生實(shí)現(xiàn)
Chrome 76 將原生支持圖片的惰性加載,支持對img和iframe進(jìn)行延遲加載,只需要將loading屬性設(shè)置為lazy即可。
<img?src="celebration.jpg"?loading="lazy"?alt="..."?/>
<iframe?src="video-player.html"?loading="lazy">iframe>
原生實(shí)現(xiàn)的好處是,不需要任何腳本,純原生HTML即可,簡單方便,支持多種屬性
lazy:對資源進(jìn)行延遲加載。 eager:立即加載資源。 auto:瀏覽器自行判斷決定是否延遲加載資源。
原生的壞處就是在于瀏覽器的支持率不是很高,將來肯定是非常好的。

我們知道由于瀏覽器的支持率不是很好,上面的方案固然很好,但是使用的并不是很多,所以下面介紹幾種更加常見的懶加載方案。
2、Element.getBoundingClientRect()
getBoundingClientRect返回值是一個(gè) DOMRect 對象,這個(gè)對象是由該元素的 getClientRects() 方法返回的一組矩形的集合, 即:是與該元素相關(guān)的CSS 邊框集合 。DOMRect 對象包含了一組用于描述邊框的只讀屬性——left、top、right和bottom,單位為像素。除了 width 和 height 外的屬性都是相對于視口的左上角位置而言的。

有了這個(gè)API后我們很同意獲取圖片的top值,當(dāng)top值小于可視區(qū)的高度的時(shí)候就可以任何圖片進(jìn)入了可視區(qū),直接加載圖片即可
element.getBoundingClientRect().top?document.documentElement.clientHeight
由于需要在滾動(dòng)的時(shí)候去監(jiān)聽圖片的位置,所以我們需要使用到window.onscroll事件,我們在事件內(nèi)部處理相關(guān)的邏輯即可。
3、通過相對計(jì)算獲取元素位置
通過document.documentElement.clientHeight獲取屏幕可視窗口高度。 通過element.offsetTop獲取元素相對于文檔頂部的距離。 通過document.documentElement.scrollTop獲取瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動(dòng)條滾動(dòng)的距離。然后判斷2-3<1是否成立,如果成立,元素就在可視區(qū)域內(nèi)。
element.offsetTop?-??document.documentElement.scrollTop?document.documentElement.clientHeight
此方法也需要在滾動(dòng)的時(shí)候去監(jiān)聽圖片的位置,所以我們需要使用到window.onscroll事件,我們在事件內(nèi)部處理相關(guān)的邏輯即可。
4、使用IntersectionObserver
const?observer?=?new?IntersectionObserver(callback,?observerConfig)
const?imgList?=?document.querySelectorAll(".lazyload");
const?observer?=?new?IntersectionObserver(entries?=>?{
????entries.forEach(item?=>?{
????????if?(item.isIntersecting)?{
????????????item.target.src?=?item.target.dataset.origin;?//?判斷在可視區(qū)了,把data-origin的值放到src
????????????observer.unobserve(item.target);?//?已經(jīng)加載過的圖片停止進(jìn)行監(jiān)聽
????????}
????});
});
imgList.forEach(item?=>?observer.observe(item));
補(bǔ)充
1、優(yōu)化
由于上面某些情況是需要使用到window.scroll事件的,所以我們可以增加節(jié)流來減少事件處理函數(shù)的調(diào)用次數(shù)。假設(shè)我們判斷是否可視區(qū)邏輯為函數(shù)loadImage那么我們可以如下處理。
window.onscroll?=?throttle(loadImage,?500)
2、拓展
上面后續(xù)三種方法不僅僅可以使用在圖片的懶加載上面,其實(shí)所有可以懶加載的地方都可以通過這種方式進(jìn)行判斷,比如列表分頁加載,我們可以通過這種方式進(jìn)行判斷是否需要進(jìn)行下一頁的加載,比如我們需要埋曝光埋點(diǎn)的時(shí)候,可以通過這種方法判斷元素是否曝光,進(jìn)行埋點(diǎn)事件的觸發(fā)。
我組建了一個(gè)氛圍特別好的 Node.js 社群,里面有很多 Node.js小伙伴,如果你對Node.js學(xué)習(xí)感興趣的話(后續(xù)有計(jì)劃也可以),我們可以一起進(jìn)行Node.js相關(guān)的交流、學(xué)習(xí)、共建。下方加 考拉 好友回復(fù)「Node」即可。
???“分享、點(diǎn)贊、在看” 支持一波??
