【短文】手寫實現基本的圖片懶加載

文章代碼可在這裏下載.css

原理

先不給圖片設置 src屬性值, 當圖片進入瀏覽器窗口的時,給圖片的src屬性賦值, 開始請求圖片並渲染至屏幕。html

方案

  • 給將每張圖片加上一個data-src屬性來保存正確的圖片連接,將src屬性設置爲空(或默認圖片連接)
  • 將全部須要延遲加載的圖片用一個盒子包起來,設置寬高和默認的佔位符,把原來的位置撐起來
  • 等到其餘資源都加載完成以後,觀察圖片是否在視窗以內,決定是否開始加載圖片,便是否給src屬性賦予正確的值
  • 對於圖片數量不少的狀況,須要在頁面滾動的時候判斷是否須要對圖片進行加載,在當前圖片區域徹底展現出來後再加載真實圖片,即包裹圖片的盒子底部出如今視窗以內時開始加載圖片

方案圖示

如今有一個須要解決的問題:怎麼知道圖片是否在視窗以內呢?git

能夠這樣判斷:當圖片的底部和頁面的頂部的距離小於視窗的底部和頁面的頂部的距離時就能夠認爲圖片已經進入視窗了。這樣提及來有些繞,用圖片來看看會更清晰。api

當視窗在下拉過程當中其底部低於圖片的底部時,就認爲圖片已經要加載了: 數組

代碼實現

實現單張圖片的懶加載

爲方便說明,先實現單張圖片的懶加載,使用 JQuery庫來完成。瀏覽器

JQuery的api中能夠獲取到視窗的高度、視窗頂部和頁面頂部的距離,兩者相加就是視窗底部和頁面頂部的距離;一樣的,也能夠得到圖片包裹層的高度和它的頂部到頁面頂部的距離,相加就是圖片包裹層底部到頁面頂部的距離。網絡

將以上兩者比較,就能夠肯定圖片是否須要被加載。app

  • DOM結構框架

    <div class="wrap-single">
        <img src="" data- src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
    </div>
    複製代碼
  • 圖片初始樣式ui

    img {
        width: 100%;
        display: none;
        /* 加載以前先隱藏 */
    }
    複製代碼
  • JQuery代碼

    let $wrap = $('.wrap-single'),
        img = $wrap.children('img'),
        $window = $(window);
    
    $window.on('load scroll', function(e) { // 同時監聽 加載完成和滾動 事件
        if(img.attr('is-loaded') === 'true') { // 當圖片被打上已加載的標記時再也不進行請求
            return ;
        }
        // 獲取圖片容器自己的高度 + border-top距離body 頂部的高度
        let wrapBottomDist= $wrap.outerHeight() + $wrap.offset().top;
        // 獲取視窗自己的高度 + 視窗頂部距離 body 頂部的高度
        let windowBottomDist = $window.outerHeight() + $window.scrollTop();
        // 判斷圖片容器是否已在視窗之中
        if(wrapBottomDist <= windowBottomDist) {
            // 如果,則取得真實圖片地址並設置給 src 屬性
            let realSrc = img.attr('data-src');
            img.attr('src', realSrc);
            // 當圖片加載完成時,設置圖片顯示,並標記圖片已經加載完成
            img.on('load', () => {
                img.css('display', 'block');
                img.attr('is-loaded', true); // 利用自定義屬性打上加載完成的標記
            });
        }
    });
    複製代碼

    效果以下:

可見只有當圖片徹底進入窗口時纔會開始請求圖片,同時從右側能夠看出當圖片進入窗口是纔會發出對圖片連接的請求。

多張圖片的懶加載

在有了單張圖片懶加載的基礎後,實現多張圖片的懶加載就容易多了。直接給出代碼吧,代碼中有詳細的註釋:

  • DOM 結構

    <div class="wrap">
        <h1>A Lazy Load Demo</h1>
        <div class="img-wrapper">
            <img src="" data-src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
        </div>
        
        <!-- 省略多行一樣的代碼 -->
        
        <div class="img-wrapper">
            <img src="" data-src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg">
        </div>
    </div>
    複製代碼
  • JQuery 代碼

    let $boxes = $('.img-wrapper'),
        $window = $(window),
        imgs = [], // 保存每張圖片的對象
        wrapBottomDist = []; // 保存每張圖片底部與 body 頂部的距離
    
    $boxes.each((index, item) => { // 處理數組 imgs 和 wrapBottomDist
        let $item = $(item);
        imgs.push($item.children('img'));
        wrapBottomDist.push($item.outerHeight() + $item.offset().top); // 獲取圖片容器自己的高度 + border-top距離body 頂部的高度
    });
    
    function lazy() { // 事件處理程序
        // 判斷是否須要繼續執行
        if(!wrapBottomDist.length || !wrapBottomDist[wrapBottomDist.length - 1]) {
            return ;
        }
        // 獲取視窗自己的高度 + 視窗頂部距離 body 頂部的高度
        let windowBottomDist = $window.outerHeight() + $window.scrollTop();
        // 一次判斷每張圖片是否已經進入視窗
        wrapBottomDist.forEach((pos, index) => {
            if(pos < windowBottomDist) {
                let img = imgs[index];
                img.attr('src', img.attr('data-src'));
                img.on('load', () => {
                    img.css('display', 'block');
                });
    
                wrapBottomDist[index] = undefined; // 將已經進入視窗的項進行標記
            }
        });
    }
    
    $window.on('load scroll', lazy); // 註冊事件處理程序
    複製代碼

    效果

簡單總結

  1. 以上實現了基本的懶加載框架,還能夠加入防抖、節流等策略實現對滑動事件的處理
  2. 懶加載能夠減小初次加載網頁的網絡請求數量,使網頁加載速度更快;同時能夠實現必定的按需加載,節省流量
  3. 本文僅實現懶加載的基本代碼,在現實應用中還有許多待改進的地方。

若有錯誤,敬請指出,謝謝~

相關文章
相關標籤/搜索