圖片懶加載的幾種方法

在一些圖片比較多的網(wǎng)站會(huì)用到 圖片懶加載 技術(shù),這項(xiàng)技術(shù)可以延遲加載圖像荠呐,只當(dāng)圖片出現(xiàn)在我們看到的視圖中才加載挥吵,它的好處是大大提高用戶體驗(yàn),節(jié)省不必要的資源浪費(fèi)以及網(wǎng)站的性能提升等祭椰。下面介紹幾種圖片懶加載的方法臭家,分別是監(jiān)聽(tīng) scroll、resize 事件方淤,使用 Intersection Observer API 以及 Chrome70 自帶的懶加載設(shè)置钉赁。任何技術(shù)都是為解決問(wèn)題服務(wù)的。在開(kāi)始之前携茂,還是要了解清楚「是什么」以及「為什么」你踩。

什么是懶加載

當(dāng)一個(gè)網(wǎng)站的圖片數(shù)量較多時(shí),直接加載可能會(huì)有很大的開(kāi)銷讳苦,不利于性能带膜,這時(shí)可以將所有的圖片換成輕量的占位圖,不加載圖片鸳谜。而當(dāng)用戶真正滾動(dòng)到圖片出現(xiàn)時(shí)膝藕,再迅速將占位圖片換成真正我們想展示的圖片,這整個(gè)過(guò)程就是懶加載咐扭。

為什么要懶加載

當(dāng)你打開(kāi)一個(gè)網(wǎng)站時(shí)芭挽,瀏覽器會(huì)做許多工作滑废,這其中包括下載各種可能用到的資源,然后渲染呈現(xiàn)在你面前览绿,假設(shè)你的網(wǎng)站有大量的圖片策严,那么加載的過(guò)程是很耗時(shí)的,尤其像那些新聞資訊類需要大量圖片的網(wǎng)站饿敲,可想而知妻导,網(wǎng)站的初始加載時(shí)間會(huì)很長(zhǎng),再加上網(wǎng)絡(luò)等其它影響怀各,用戶體驗(yàn)會(huì)很差倔韭,相信你經(jīng)常遇到過(guò)一個(gè)網(wǎng)站卡在某個(gè)地方,一直在加載瓢对,這種體驗(yàn)很不好寿酌。我們都希望一輸入網(wǎng)址,頁(yè)面立馬就呈現(xiàn)在眼前硕蛹。

既然想要頁(yè)面立馬呈現(xiàn)在面前醇疼,那勢(shì)必要減少瀏覽器的負(fù)荷,優(yōu)化代碼法焰,減少一些不必要的請(qǐng)求和不必要資源的加載秧荆,因?yàn)槟愦蜷_(kāi)網(wǎng)站的時(shí)候,瀏覽器會(huì)把所有可能的資源都下載好埃仪,而實(shí)際上有些資源你并不需要用到乙濒,這就造成了浪費(fèi)。所以有必要在一些資源上做下優(yōu)化卵蛉,提高網(wǎng)站加載速度颁股。

滾動(dòng)事件監(jiān)聽(tīng)

前面說(shuō)到要等圖片出現(xiàn)在視口時(shí)才加載,那么肯定要監(jiān)控瀏覽器的 scroll 事件傻丝,并且要計(jì)算圖片與瀏覽器窗口的距離來(lái)選擇替換圖片的 src 地址甘有。代碼如下:

HTML
<div>
  <img class="lazy-load" data-src="https://source.unsplash.com/random/600" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/700" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/800" alt="">
  <img class="lazy-load" data-src="https://source.unsplash.com/random/900" alt="">
</div>
// 引入 lodash 庫(kù)
<script src="https://cdn.bootcss.com/lodash.js/4.17.12-pre/lodash.core.min.js"></script>  
CSS
div {
  margin-top: 350px;
}
.lazy-load {
  width: 200px;
  height: 150px;
}
JS
let lazyImages = [...document.querySelectorAll('.lazy-load')]
let inAdvance = 300
function lazyLoad() {
    lazyImages.forEach(image => {
        if (image.offsetTop < window.innerHeight + window.pageYOffset + inAdvance) {
            image.src = image.dataset.src;   // 替換真實(shí)圖片的  URL
        }
    })
}
lazyLoad();
window.addEventListener('scroll', _.throttle(lazyLoad, 50))
window.addEventListener('resize', _.throttle(lazyLoad, 50))

這其中有幾個(gè)屬性,首先是 data-src桑滩,它是自定義屬性梧疲,可以在 js 里通過(guò) dataset 獲得它的屬性值;還有 offsetTop ,innerHeight 以及 pageYOffset 屬性运准,你可以通過(guò) MDN 文檔查詢他們的定義和用法;最后是 _.throttle 函數(shù)缭受,它是一個(gè)節(jié)流函數(shù)胁澳,引用自 lodash 庫(kù),因?yàn)楸O(jiān)聽(tīng) scroll 滾動(dòng)以及 resize 窗口改變事件會(huì)不斷地觸發(fā)米者,過(guò)于頻繁韭畸,所以使用節(jié)流函數(shù)讓其每隔一段時(shí)間執(zhí)行宇智,節(jié)省開(kāi)銷。

Intersection Observer API

現(xiàn)在胰丁,有一個(gè) Intersection observer 接口可以方便我們操作随橘,它可以異步觀察目標(biāo)元素與祖先元素或頂層文件的交集變化。簡(jiǎn)單的說(shuō)锦庸,以前我們需要自己去寫滾動(dòng)監(jiān)聽(tīng)事件函數(shù)机蔗,現(xiàn)在,這個(gè) API 可以幫助我們甘萧,我們只需要統(tǒng)一寫一個(gè) 觀察函數(shù) 萝嘁,每當(dāng)想觀察的元素進(jìn)入視口,也就是我們看見(jiàn)它時(shí)扬卷,就執(zhí)行相應(yīng)的操作牙言。看看以下 js 代碼:

<style>   // css 部分
  .lazy-load {
     width: 400px;
     height: 300px;
   }
</style>
<div>
    <img class="lazy-load" data-src="https://source.unsplash.com/random/600" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/700" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/800" alt="">
    <img class="lazy-load" data-src="https://source.unsplash.com/random/900" alt="">
</div>
document.addEventListener("DOMContentLoaded", function() {
    let lazyImages = [...document.querySelectorAll('.lazy-load')];
    if ("IntersectionObserver" in window) {
        // 創(chuàng)建一個(gè)觀察函數(shù)怪得,以便待會(huì)調(diào)用   
        let lazyImageObserver = new IntersectionObserver(function(entries, observer) {
            entries.forEach(function(entry) {
            if (entry.isIntersecting) {
               let lazyImage = entry.target;
               lazyImage.src = lazyImage.dataset.src;   // 替換 src URL
               lazyImageObserver.unobserve(lazyImage);  // 解除觀察
            }
            });
        });
        // 對(duì)所有需要懶加載的圖片進(jìn)行 “暗中觀察”
        lazyImages.forEach(function(lazyImage) {
            lazyImageObserver.observe(lazyImage);
        });
     }else{
           alert('您的瀏覽器不支持 IntersectionObserver');
     }
});

可以看到咱枉,里面監(jiān)聽(tīng)了 DOMContentLoaded 事件,當(dāng)初始的 HTML 文檔被完全加載和解析完成之后徒恋,這個(gè)事件就被觸發(fā)蚕断,在頁(yè)面初始之后獲取到所有圖片元素,然后進(jìn)行觀察因谎。

那既然這個(gè) API 這么好基括,又簡(jiǎn)便易用,有沒(méi)什么缺點(diǎn)呢财岔?相信你看了上面的代碼就能知曉风皿,對(duì),瀏覽器兼容問(wèn)題=宠怠桐款!

can I use

可以看到,還是有很多泛紅夷恍,只有 Chrome 支持的最好魔眨,從 58 以上版本就完全支持了,F(xiàn)irefox 也不錯(cuò)酿雪。如果你的項(xiàng)目不需要考慮兼容的話遏暴,可以嘗試使用下它,看看效果指黎。

Chrome 瀏覽器自帶

這個(gè)方法厲害了朋凉,沒(méi)有前面兩種方法那么復(fù)雜,它是 Chrome 自帶的原生 lazyload 屬性醋安,只需要一個(gè)開(kāi)關(guān)杂彭。

chrome://flags/#enable-lazy-image-loading

復(fù)制它到 Chrome 瀏覽器的地址欄墓毒,然后找到如下選項(xiàng),將其設(shè)置為「Enabled」亲怠。


image

然后在 HTML 標(biāo)簽里開(kāi)啟:

<img src="https://source.unsplash.com/random/600" alt="" lazyload="on">

不需要多余的代碼所计,不需要 JS ,簡(jiǎn)直強(qiáng)大团秽。

比較三者

秉承著嘗試搗鼓新技術(shù)的原則主胧,應(yīng)該優(yōu)先使用 Intersection Observer ,隨著越來(lái)越多的瀏覽器支持會(huì)更廣泛地應(yīng)用;但如果要考慮瀏覽器的兼容問(wèn)題徙垫,那就要使用平常的 scroll,resize 事件監(jiān)聽(tīng)了讥裤,配合 offsetTop 、innerHeight 以及 pageYOffset 幾個(gè)屬性實(shí)現(xiàn)姻报。至于最簡(jiǎn)單粗暴的那個(gè)方法己英,很明顯只能在特定的 Chrome 70 以上版本中使用,有很大的局限性吴旋,不過(guò)現(xiàn)在使用 Chrome 的人非常的多损肛,所以也是有用處的。
綜合來(lái)看荣瑟,應(yīng)該將 Intersection Observerscroll,resize 結(jié)合起來(lái)使用治拿,這可能是最優(yōu)也最兼容的方案。

參考資料

[1] MDN 文檔:https://developer.mozilla.org/zh-CN/docs/Web/API/Intersection_Observer_API
[2] 延遲加載圖像和視頻:https://developers.google.com/web/fundamentals/performance/lazy-loading-guidance/images-and-video/
[3] Lazy load images:https://medium.com/@filipvitas/lazy-load-images-with-zero-javascript-2c5bcb691274

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末笆焰,一起剝皮案震驚了整個(gè)濱河市劫谅,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌嚷掠,老刑警劉巖捏检,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異不皆,居然都是意外死亡贯城,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門霹娄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)能犯,“玉大人,你說(shuō)我怎么就攤上這事犬耻〔染В” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵枕磁,是天一觀的道長(zhǎng)合瓢。 經(jīng)常有香客問(wèn)我,道長(zhǎng)透典,這世上最難降的妖魔是什么晴楔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮峭咒,結(jié)果婚禮上税弃,老公的妹妹穿的比我還像新娘。我一直安慰自己凑队,他們只是感情好则果,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著漩氨,像睡著了一般西壮。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上叫惊,一...
    開(kāi)封第一講書(shū)人閱讀 49,144評(píng)論 1 285
  • 那天款青,我揣著相機(jī)與錄音,去河邊找鬼霍狰。 笑死抡草,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蔗坯。 我是一名探鬼主播康震,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宾濒!你這毒婦竟也來(lái)了腿短?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤绘梦,失蹤者是張志新(化名)和其女友劉穎橘忱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體谚咬,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鹦付,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了择卦。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片敲长。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖秉继,靈堂內(nèi)的尸體忽然破棺而出祈噪,到底是詐尸還是另有隱情,我是刑警寧澤尚辑,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布辑鲤,位于F島的核電站,受9級(jí)特大地震影響杠茬,放射性物質(zhì)發(fā)生泄漏月褥。R本人自食惡果不足惜弛随,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望宁赤。 院中可真熱鬧舀透,春花似錦、人聲如沸决左。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)佛猛。三九已至惑芭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間继找,已是汗流浹背遂跟。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留码荔,地道東北人漩勤。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像缩搅,于是被迫代替她去往敵國(guó)和親越败。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 特別聲明:此篇文章內(nèi)容來(lái)源于@Jeremy Wagner的《Lazy Loading Images and Vid...
    Naeco閱讀 30,662評(píng)論 0 32
  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)堂鲤。 注意:講述HT...
    kismetajun閱讀 27,424評(píng)論 1 45
  • 第一日 與你說(shuō)星稀月朗 與你詩(shī)詞共賞 你說(shuō)桃李滿村落 我說(shuō)花事香了老街坊 第二日 彩虹出岫共天長(zhǎng) 你說(shuō)錯(cuò)過(guò)的光景下...
    敢問(wèn)姑娘芳齡閱讀 311評(píng)論 0 0
  • 蘇小今閱讀 136評(píng)論 0 0
  • 我還在探索黑暗中的隱秘 把新大陸說(shuō)給星星聽(tīng) 月光時(shí)常都很朦朧 就像我和世界的距離 有人說(shuō) 可以為孤獨(dú)加冕 但我并不...
    云中飄舞閱讀 2,133評(píng)論 57 74