惰性加載

關於惰性加載


在講圖片的惰性加載前,我們先來聊聊惰性加載。惰性加載又稱爲延遲加載、懶加載等,還有個好聽的英文名字叫做 "lazyload"。需要注意的是,惰性加載並不只是圖片的專利,Javascript 中函數也有惰性加載的概念,而在 Javascript 異步加載中還有個 LazyLoad類庫,而圖片的惰性加載庫(lazyload)與之完全是兩個概念,這些一定要弄清楚,以免混淆概念。

圖片的惰性加載是啥意思?爲什麼要用它?當我們頁面上的東西越來越豐富的時候,我們發現頁面的加載速度卻越來越慢,而圖片的加載量無疑是 HTTP 請求裏面的大頭。其實很多時候,你把整個頁面加載完,用戶卻不會滑動到最下面,也就是說很多東西其實白白加載了。因爲圖片的加載是大頭,所以我們先拿圖片開刀,我們假設,如果試圖加載一個 HTML 頁面,圖片先不加載,當用戶將頁面往下滑動,圖片該出現在可視區域時,再將該圖片加載,這樣就能將一開始打開頁面的 HTTP 請求量降低,這就是圖片的惰性加載。

實現


圖片的惰性加載實現方式其實很簡單。

  • 在 HTML 文件中將需要惰性加載的圖片的 src 屬性置爲一個相同的地址(一般設置爲一張 loading 圖),這樣這張圖只會加載一次(第二次即會讀取緩存),或者乾脆置爲空(用戶體驗不好),將真實的圖片地址存儲在別的屬性中(比如 data-original 屬性)
  • 監聽事件(比如 scroll 事件),判斷需要惰性加載的圖片是否已經在可視區域,如果是,則將 src 屬性替換成 data-original 屬性值

接着我們來簡單寫下代碼。

首先,按照第一步將真實的圖片地址藏在 data-original 屬性中。這裏我假設所有圖片都要進行惰性加載,現實開發中如果肯定是在第一屏的圖片,它的 src 完全可以直接指向真實的地址。

<ul>
  <li class='lazy'><img data-original='images/0.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/1.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/2.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/3.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/4.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/5.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/6.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/7.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/8.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/9.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/10.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/11.jpg' src='images/loading.gif'/></li>
  <li class='lazy'><img data-original='images/12.jpg' src='images/loading.gif'/></li>
</ul>
View Code
 

因爲我把所有圖片都設置爲惰性加載模式,而首屏的圖片需要直接顯示,這裏我寫了個 init() 函數,註釋都在代碼中了:

function init() {
  var images = document.images;
  // 加載首屏圖片
  for (var i = 0, len = images.length; i < len; i++) {
    var obj = images[i];
    // 如果在可視區域並且還沒被加載過
    if (obj.getBoundingClientRect().top < document.documentElement.clientHeight && !obj.isLoad) {
      obj.isLoad = true;
      // 先調用 HTML5 方法
      if (obj.dataset) 
        imageLoaded(obj, obj.dataset.original);
      else 
        imageLoaded(obj, obj.getAttribute('data-original'));
    } else {  // 假設圖片標籤在 HTML 中的順序和實際頁面中順序一致
      break;
    }
  }
}
View Code

 

代碼中寫了個 imageLoaded() 函數來將真實的圖片地址指向元素,如果直接將 data-original 屬性值指向圖片的 src 屬性的話,看到的圖片可能會一段一段出現,而先將圖片完全加載,然後再賦值使圖片出現的話,體驗就好多了。

function imageLoaded(obj, src) {
  var img = new Image();
  img.onload = function() {
    obj.src = src;
  };
  img.src = src;
}

 

OK,接着我們監聽 scroll 事件。當用戶滑動頁面,圖片出現在可視區域時,隨即加載圖片。

window.onscroll = function() {
  lazyload();
};

function lazyload() {
  var lazy = 0;
  var images = document.images;
  for (var i = 0, len = images.length; i < len; i++) {
    var obj = images[i];
    if (obj.getBoundingClientRect().top - lazy < document.documentElement.clientHeight && !obj.isLoad) {
      obj.isLoad = true;
      if (obj.dataset) 
        imageLoaded(obj, obj.dataset.original);
      else 
        imageLoaded(obj, obj.getAttribute('data-original'));
    }
  }
}

 

有的時候並不能當圖片剛好在可視區域的時候再去加載,而要稍微 "預加載",可以調整下 lazyload() 函數中的 lazy 參數。

如果 "生硬" 地顯示圖片體驗不大好,也可以搞點淡出效果,具體就不說了,可以看完整代碼 Github

這樣,一個簡單的圖片惰性加載 DEMO 就完成了!

PS:惰性加載雖然好處多多,但是也有一個 "非致命" 的缺點,影響 SEO。因爲圖片都被替換成假的圖片,所以會影響圖片的收錄,所以這功能不建議在詳情頁使用

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章