手摸手教你實現圖片懶加載

懶加載(Lazy-Load)。它是針對圖片加載時機的優化:在一些圖片量比較大的網站(好比電商網站首頁,或者團購網站、小遊戲首頁等),若是咱們嘗試在用戶打開頁面的時候,就把全部的圖片資源加載完畢,那麼極可能會形成白屏、卡頓等現象,由於圖片真的太多了,一口氣處理這麼多任務,瀏覽器作不到啊!

目的

懶加載 的目的是當頁面的圖片進入到用戶的可視範圍以內在加載圖片的一種優化方式。html

能夠增長首屏加載的速度,畢竟,用戶點開頁面的瞬間,呈現給他的只是首屏,咱們只要把首屏的資源圖片加載處理就能夠了,至於下面的圖片,當用戶下滑噹噹前位置的時候,在加載出來也是沒問題的,對於性能壓力也小了,用戶體驗也沒有變差。前端

原理

在頁面初始化的時候,
<img>圖片的src其實是放在data-src屬性上的,當元素處於可視範圍內的時候,就把data-src賦值給src屬性,完成圖片加載。瀏覽器

// 在一開始加載的時候
<img data-src="http://xx.com/xx.png" src="" />

// 在進入可視範圍內時
<img data-src="http://xx.com/xx.png" src="http://xx.com/xx.png" />

<div>使用背景圖來實現,原理也是同樣的,把background-image放在,在可視範圍時,就把data-src賦值給src屬性,完成圖片加載。性能優化

// 在一開始加載的時候
<div
  data-src="http://xx.com/xx.png"
  style="background-image: none;background-size: cover;"
></div>

// 在進入可視範圍內時
<div
  data-src="http://xx.com/xx.png"
  style="background-image: url(http://xx.com/xx.png);background-size: cover;"
></div>

實現一個懶加載

基於上面的實現思路,本身實現一個懶加載。網絡

新建一個 index.html 中,爲這些圖片預置 img 標籤:前端性能

<head>
  <style>
    .img {
      width: 200px;
      height: 200px;
      background-color: gray;
      margin-bottom: 20px;
    }

    .pic {
      width: 100%;
      height: 100%;
    }
  </style>
</head>
<!-- 圖片來自網絡,侵刪。 -->

<body>
  <div class="container">
    <div class="img">
      <!-- 注意咱們並無爲它引入真實的src -->
      <img
        class="pic"
        alt="加載中"
        data-src="https://tse1-mm.cn.bing.net/th/id/OIP.8OrEFn_rKe82kqAWFjTuMwHaEo?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://ssl.tzoo-img.com/images/tzoo.94911.0.910013.seoul-nami.jpg?width=1080"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://tse4-mm.cn.bing.net/th/id/OIP.ZitgAuABnwkrGn4lid2ZmQHaEK?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="http://pic34.photophoto.cn/20150315/0034034862056002_b.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="http://img.mp.sohu.com/upload/20170724/32d4409f34194b029ed287abf1c99b70_th.png"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075991913520.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://tse4-mm.cn.bing.net/th/id/OIP.PZdPKj3sXEX2jLrepx3MUwHaEo?pid=Api&rs=1"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075831439349.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://pic6.wed114.cn/20180829/2018082910075468043336.jpg"
      />
    </div>
    <div class="img">
      <img
        class="pic"
        alt="加載中"
        data-src="https://tse2-mm.cn.bing.net/th/id/OIP.CRYz5Bv4vylsMh83G4CsLgHaFj?pid=Api&rs=1"
      />
    </div>
  </div>
</body>

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

當前可視區域的高度,在現代瀏覽器及 IE9 以上的瀏覽器中,可使用window.innerHeight屬性獲取,在低版本的 IE 中使用document.documentElment.clientHeight 獲取,這裏咱們兼容兩種狀況:性能

const viewHeight = window.innerHeight || document.documentElement.clientHeight;

元素距離可視區域頂部的高度,這裏咱們用 getBoundingClientRect()方法來獲取返回元素的大小和相對於尺寸的位置,對於該 API,MDN 的解釋是:優化

Element.getBoundingClientRect() 方法返回元素的大小及其相對於視口的位置。

返回的屬性中有一個相對於可視區域頂部的高度也就是top屬性,恰好就是咱們須要的元素距離頂部的距離。網站

這樣,兩個屬性就都獲得了。

咱們利用當前可視區域的高度大於等於元素距離可視區域頂部的高度就能夠肯定,該元素是否已經進入到了可視範圍:

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

  function lazyload() {
    console.log("滾動...");
    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;
      }
    }
  }

  // 防抖函數
  function debounce(fn, delay = 500) {
    let timer = null;
    return function (...args) {
      if (timer) clearTimeout(timer);
      timer = setTimeout(() => {
        fn.call(this, args);
      }, delay);
    };
  }

  // 是的頁面初始化是加載首屏圖片
  window.onload = lazyload;
  // 監聽Scroll事件,爲了防止頻繁調用,使用防抖函數優化一下
  window.addEventListener("scroll", debounce(lazyload, 600), false);
</script>

小結

  1. 先收集到頁面中全部的img(也能夠用class)。
  2. 獲取到視圖高度,計算顯示的img,避免重複賦值src
  3. 當滑動向下滑動鼠標,會觸發onScroll事件(防抖),而後觸發計算是否賦值src

參考資料

相關文章
相關標籤/搜索