1. 程式人生 > >優化首屏體驗——Lazy-Load 初探

優化首屏體驗——Lazy-Load 初探

Lazy-Load


Lazy-Load,翻譯過來是“懶載入”。它是針對圖片載入時機的優化:在一些圖片量比較大的網站(比如電商網站首頁,或者團購網站、小遊戲首頁等),如果我們嘗試在使用者開啟頁面的時候,就把所有的圖片資源載入完畢,那麼很可能會造成白屏、卡頓等現象,因為圖片真的太多了,一口氣處理這麼多工,瀏覽器做不到啊!

但我們再想,使用者真的需要這麼多圖片嗎?不對,使用者點開頁面的瞬間,呈現給他的只有螢幕的一部分(我們稱之為首屏)。只要我們可以在頁面開啟的時候把首屏的圖片資源加載出來,使用者就會認為頁面是沒問題的。至於下面的圖片,我們完全可以等使用者下拉的瞬間再即時去請求、即時呈現給他。這樣一來,效能的壓力小了,使用者的體驗卻沒有變差——這個延遲載入的過程,就是 Lazy-Load。

最直觀的應該是淘寶首頁的 HTML Preview 效果:

我們看到,這個還沒來得及被圖片填充完全的網頁,是用大大小小的空 div 元素來佔位的。掘金首頁也是如此。

一旦我們通過滾動使得這個 div 出現在了可見範圍內,那麼 div 元素的內容就會發生變化,呈現如下的內容:


<p>style="background-image: url(&quot;https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1&quot;); background-size: cover;"</p>

可以看出,style 內聯樣式中的背景圖片屬性從 none 變成了一個線上圖片的 URL。也就是說,出現在可視區域的瞬間,div 元素的內容被即時地修改掉了——它被寫入了有效的圖片 URL,於是圖片才得以呈現。這就是懶載入的實現思路。

 

動手寫一個Lazy-Load

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Lazy-Load</title>
  <style>
    .img {
      width: 200px;
      height:200px;
      background-color: gray;
    }
    .pic {
    // 必要的img樣式
    }
  </style>
</head>
<body>
<div class="container">
  <div class="img">
    // 注意我們並沒有為它引入真實的src
    <img class="pic" alt="載入中" data-src="./images/1.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/2.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/3.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/4.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/5.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/6.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/7.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/8.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/9.png">
  </div>
  <div class="img">
    <img class="pic" alt="載入中" data-src="./images/10.png">
  </div>
</div>
</body>
</html>

 

在懶載入的實現中,有兩個關鍵的數值:一個是當前可視區域的高度,另一個是元素距離可視區域頂部的高度

當前可視區域的高度, 在和現代瀏覽器及 IE9 以上的瀏覽器中,可以用 window.innerHeight 屬性獲取。在低版本 IE 的標準模式中,可以用 document.documentElement.clientHeight 獲取,這裡我們相容兩種情況:

<script>
    const viewHeight = window.innerHeight || document.documentElement.clientHeight
</script>

元素距離可視區域頂部的高度,我們這裡選用 getBoundingClientRect() 方法來獲取返回元素的大小及其相對於視口的位置。對此 MDN 給出了非常清晰的解釋:

         該方法的返回值是一個 DOMRect 物件,這個物件是由該元素的 getClientRects() 方法返回的一組矩形的集合, 即:是與該元素相關的 CSS 邊框集合 。

         DOMRect 物件包含了一組用於描述邊框的只讀屬性——left、top、right 和 bottom,單位為畫素。除了 width 和 height 外的屬性都是相對於視口的左上角位置而言的。

 

具體實現程式碼如下:

<script>
  // 獲取所有的圖片標籤
  const imgs = document.getElementsByTagName('img')
  // 獲取可視區域的高度
  const viewHeight = window.innerHeight || document.documentElement.clientHeight
  // num用於統計當前顯示到了哪一張圖片,避免每次都從第一張圖片開始檢查是否露出
  let num = 0

  function lazyload () {
    for (let i = num; i < imgs.length; i++) {
      // 用可視區域高度減去元素頂部距離可視區域頂部的高度
      let distance = viewHeight - imgs[i].getBoundingClientRect().top
      // 如果可視區域高度大於等於元素頂部距離可視區域頂部的高度,說明元素露出
      if (distance >= 0) {
        // 給元素寫入真實的src,展示圖片
        imgs[i].src = imgs[i].getAttribute('data-src')
        // 前i張圖片已經載入完畢,下次從第i+1張開始檢查是否露出
        num = i + 1
      }
    }
  }

  // 監聽Scroll事件
  window.addEventListener('scroll', lazyload, false)
</script>

更多的乾貨請點選這裡 https://blog.csdn.net/woleigequshawanyier

歡迎各位看官的批評和指正,共同學習和成長

希望該文章對您有幫助,也希望得到您的鼓勵和支援