Lazy-Load 初探

Lazy-Load 初相見

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

但咱們再想,用戶真的須要這麼多圖片嗎?不對,用戶點開頁面的瞬間,呈現給他的只有屏幕的一部分(咱們稱之爲首屏)。只要咱們能夠在頁面打開的時候把首屏的圖片資源加載出來,用戶就會認爲頁面是沒問題的。至於下面的圖片,咱們徹底能夠等用戶下拉的瞬間再即時去請求、即時呈現給他。這樣一來,性能的壓力小了,用戶的體驗卻沒有變差——這個延遲加載的過程,就是 Lazy-Load。web

如今咱們打開掘金首頁:面試

你們留意一欄文章右側可能會出現的圖片,這裏我們給個特寫:瀏覽器

你們如今以儘量快的速度,瘋狂向下拉動頁面。發現什麼?是否是發現咱們圖示的這個圖片的位置,會出現閃動——有時候咱們明明已經拉到目標位置了,文字也呈現完畢了,圖片卻慢半拍才顯示出來。這是由於,掘金首頁也採用了懶加載策略。當咱們的頁面並未滾動至包含圖片的 div 元素所在的位置時,它的樣式是這樣的:bash

咱們把代碼提出來看一下:性能

<div data-v-b2db8566="" 
    data-v-009ea7bb="" 
    data-v-6b46a625=""   
    data-src="https://user-gold-cdn.xitu.io/2018/9/27/16619f449ee24252?imageView2/1/w/120/h/120/q/85/format/webp/interlace/1"    
    class="lazy thumb thumb"    
    style="background-image: none; background-size: cover;">  
</div>

複製代碼

咱們注意到 style 內聯樣式中,背景圖片設置爲了 none。也就是說這個 div 是沒有內容的,它只起到一個佔位的做用。優化

這個「佔位」的概念,在這個例子裏或許體現得不夠直觀。最直觀的應該是淘寶首頁的 HTML Preview 效果:網站

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

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

咱們給 style 一個特寫:

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;"

複製代碼

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

一塊兒寫一個 Lazy-Load 吧!

基於上面的實現思路,咱們徹底能夠手動實現一個屬於本身的 Lazy-Load。

此處敲黑板劃重點,Lazy-Load 的思路及實現方式爲大廠面試常考題,還望諸位同窗引發重視

首先新建一個空項目,目錄結構以下:

你們能夠往 images 文件夾裏塞入各類各樣本身喜歡的圖片。

咱們在 index.html 中,爲這些圖片預置 img 標籤:

<!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 獲取,這裏咱們兼容兩種狀況:

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

複製代碼

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

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

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

其中須要引發咱們注意的就是 left、top、right 和 bottom,它們對應到元素上是這樣的:

能夠看出,top 屬性表明了元素距離可視區域頂部的高度,正好能夠爲咱們所用!

Lazy-Load 方法開工啦!

<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>

複製代碼

小結

本節咱們實現出了一個最基本的懶加載功能。可是你們要注意一點:這個 scroll 事件,是一個危險的事件——它太容易被觸發了。試想,用戶在訪問網頁的時候,是否是能夠無限次地去觸發滾動?尤爲是一個頁面死活加載不出來的時候,瘋狂調戲鼠標滾輪(或者瀏覽器滾動條)的用戶可不在少數啊!

相關文章
相關標籤/搜索