使用交叉點觀察器延遲載入影象以提高效能【譯】

itclanCoder發表於2018-03-30

前言

本文首發於微信公眾號平臺(itclancoder),可以試試點選後方使用交叉點觀察期延遲載入影象以提高效能連結閱讀體驗會更好

在自己平時瀏覽一些大量圖片類的網站時,你會發現無論是你pc端下拉滾動條,還是移動端手動滑屏時,最終呈現的圖片有時候會有所延遲,這是一種預先載入圖片資源的方式,也就是俗稱懶載入,實現該效果,通常有兩種方式,分別是線性式(下拉窗簾式的)和漸進式(撥開晨霧見日明)圖片載入,

至於前者這裡暫且不談,本文主要是介紹後者,在本文中主要給img標籤新增一data-src屬性(實際圖片URL),以及src屬性(儲存相同影象的非常小的解析度路徑圖片),在載入圖片時,給使用者過度從模糊淡入到圖片清晰.當然更重要的是其中的js處理.如果文有誤導的地方,歡迎路過的老師多提意見和指正

圖片佔據了你網站大小的較高比例。其中一些影象位於下方,這意味著網站訪問者不會立即看到你的網站。他們需要向下滾動才能檢視影象。如果你只能顯示立即檢視的影象,然後預先載入摺疊下的影象呢?是的你可以。這就是這篇文章的內容。某處你必須看到這樣的功能在Medium上

考慮影象源

我們將在這篇文章中考慮的例子將包含5張或更多圖片,但每個圖片都會有這種結構

目錄

  1. 考慮影象源(data-src,與src)
  2. 觀察員(建立例項並使用此例項觀察DOM元素)
  3. 處理交叉路口(條目儲存所有匹配的DOM元素,呼叫loadImage獲取影象,然後適當地設定影象的src)
  4. 其他考慮事項(模糊轉換為清晰時,為影象新增淡入效果)
  5. 結論(使用漸進式圖片,你可以減少使用者資源浪費大量時間來下載內容)

程式碼:

<img src="http://res.cloudinary.com/christekh/image/upload/c_scale,h_3,w_5/v1505391130/wynand-van-poortvliet-364366_gsvyby.jpg" data-src="http://res.cloudinary.com/christekh/image/upload/c_scale,h_300,w_500/v1505391130/wynand-van-poortvliet-364366_gsvyby.jpg" >
複製程式碼

每個標籤都有一個data-src和一個src屬性

  1. data-src是我們希望讀者看到的影象的實際URL(寬度:500px)
  2. src包含相同影象的非常小的解析度(寬度:5px)。這個解析度將被拉伸以填充空間並且在真實影象載入時給訪問者模糊的效果。較小的影象比其小10倍,所以如果所有條件都正常,則會載入速度更快(10倍)

這些影象儲存在Cloudinary伺服器上,可以通過URL(h_300,w_500或h_3,w_5)輕鬆調整影象的尺寸

這是完整的HTML程式碼示例

<div class="container">
        <!-- Image 1 -->
        <img src="" data-src="" alt="">
        <!-- Image 2 -->
        <img src="" data-src="" alt="">
        <!-- Image 3 -->
        <img src="" data-src="" alt="">
        <!-- Image 4 -->
        <img src="" data-src="" alt="">
        <!-- Image 5 -->
        <img src="" data-src="" alt="">
</div>
複製程式碼

觀察員

這是完整的js程式碼:

/**
 * 
 * @authors 隨筆川跡 (itclanCode@163.com)
 * @date    2018-03-19 00:58:29
 * @version $Id$
 * @weChatPublicId ((itclanCoder))
 * @QQGroup ((643468880))
 * @PersonWeChatId ((suibichuanji))
 * @PersonQQ ((1046678249))
 * @link ((https://juejin.im/post/5a005392518825295f5d53c8))
 * @describe 使用交叉點觀察器延遲載入影象以提高效能js程式碼
 */
// 獲取img標籤元素
const images = document.querySelectorAll('img');

// 選項options
const options = {
  // 如果影象在Y軸上達到50畫素以內,請開始下載 If the image gets within 50px in the Y axis, start the download.
  root: null, // 以頁面作為根元素 Page as root
  rootMargin: '0px',
  threshold: 0.1
};
// 取得圖片
const fetchImage = (url) => {
  console.log(url);
  return new Promise((resolve, reject) => {
    const image = new Image();
    image.src = url;
    image.onload = resolve;
    image.onerror = reject;
  });
}
// 載入圖片
const loadImage = (image) => {
  const src = image.dataset.src;
  fetchImage(src).then(() => {
    // console.log(src)
    image.src = src;
  })
}
// 處理交叉路口,entries代表條目,observer觀察者
const handleIntersection = (entries, observer) => {
  entries.forEach(entry => {
    if(entry.intersectionRatio > 0) {
      console.log(entry.intersectionRatio);
      loadImage(entry.target)
    }
  })
}

// 頁面上影象的觀察者 The observer for the images on the page
const observer = new IntersectionObserver(handleIntersection, options);

images.forEach(img => {
  observer.observe(img);
})
複製程式碼

觀察者是交集觀察者的一個例項。你建立例項並使用此例項觀察DOM元素。你可以觀察元素何時進入視口

   const options = {
      rootMargin:'0px',
      threshold:0.1
   }
   const observer = new IntersectionObserver(handleIntersection,options);
複製程式碼

該例項需要一個處理程式和一個選項引數。處理程式是當匹配交叉點發生時呼叫的函式,而options引數定義了觀察者的行為。在這種情況下,我們希望處理器在影象進入視口後立即被呼叫(閾值:0.1)

你可以使用觀察者觀察頁面中的所有影象

   const images = document.querySelectorAll('img');
   images.forEach(img => {
       observer.observe(img);
    })
複製程式碼

處理交叉路口

我們為處理程式使用了一個方法,但沒有定義它。這將會像預期的那樣尖叫一個錯誤。讓我們在例項上建立處理程式

    const handleIntersection = (entries,observer) =>{
        entries.forEach(entry =>{
            if(entry.intersectionRatio > 0){
                loadImage(entry.target);
            }
        }

        )
    }

複製程式碼

該方法由帶有條目陣列和觀察者例項的API呼叫。條目儲存所有匹配的DOM元素(在這種情況下為imgs)的一個例項。如果匹配,我們用元素呼叫loadImage

loadImage獲取影象,然後適當地設定影象的src

   const loadImage = (image) => {
      const src = image.dataset.src;
      fetchImage(src).then(() => {
         image.src = src;
      })
   }

複製程式碼

它通過使用data-src值呼叫fetchImage方法來完成此操作。當實際影象返回時,它會設定image.src的值

fetchImage獲取影象並返回一個承諾

    const fetchImage = (url) => {
        return new Promise((resolve,reject) => {
           const image = new Image();
           img.src = url;
           image.onload = resolve;
           image.onerror = reject;
        })
    }

複製程式碼

其他考慮事項

考慮到流暢的使用者體驗,當從模糊轉換為清晰時,你還可以為影象新增淡入效果。如果觀看者認為載入時間較慢,這使得它更吸引眼睛

請注意,Intersection Observer在所有瀏覽器中都不被廣泛支援,因此你可能會考慮使用填充或在頁面載入後自動載入影象

   if('IntersectionObserver' in window){
      // observer code
      const observer = new IntersectionObserver(handleIntersection,options);
   }else{
       Array.from(images).forEach(image => loadImage(image))
   }
複製程式碼

結論

使用漸進式圖片,你可以減少使用者資源浪費大量時間來下載內容,其實也就是預先載入資源更小的資源,策略就是減少檔案的體積,循序漸進的載入,減少頻寬,從而提高頁面的訪問速度,這在面試當中不妨也是一種優化頁面效能的答覆,當然還有其他?若知後文,關注微信itclanCoder公眾號即可,下一篇內容繼續揭曉...

原文連結

可以試試點選後方使用交叉點觀察期延遲載入影象以提高效能連結閱讀體驗會更好

相關文章