圖片預加載、懶加載(延遲加載)

一:預加載:就是事先把網頁的圖片加載到本地,以後就直接到緩存那裏拿圖片了。html

預加載分爲有序加載和無序加載兩種。java

原網站(https://juejin.im/entry/59d79e95f265da066e176803)jquery

一、原生js實現git

1)有序加載(原生js代碼)github

        var imgs=[
            'http://pic1.win4000.com/wallpaper/9/579c3fbaa2918.jpg',
            'http://img.tuku.cn/file_big/201404/7214f32de01b4fd8b0872522ead3480b.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494524&di=9dab7ea72080994182b4e0f748c65091&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1501%2F13%2Fc0%2F1823997_1421130296700.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396544706&di=7b83b4ba4b6b4952a076bcb701a54d77&imgtype=jpg&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3804939088%2C891611583%26fm%3D214%26gp%3D0.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494761&di=b34fdf8f57cd2df851f4a38dbea91035&imgtype=0&src=http%3A%2F%2Fpic.5442.com%2F2013%2F0504%2F02%2F10.jpg'
        ];
let len = imgs.length;

/**
 * 遍歷imgs數組,將全部圖片加載出來
 * 能夠經過控制檯查看網絡請求,會發現全部圖片均已加載
 */
for (let i = 0; i < len; i++) {
    let imgObj = new Image(); // 建立圖片對象
    imgObj.src = imgs[i];

    imgObj.addEventListener('load', function () { // 這裏沒有考慮error,實際上要考慮
        console.log('imgs' + i + '加載完畢');
    }, false);
}

2)有序加載(原生js代碼):api

let len = imgs.length;

/**
 * 遍歷imgs數組,有序將全部圖片加載出來
 * 能夠經過控制檯查看網絡請求,會發現全部圖片均按順序加載
 */
let count = 0;
load();

function load() {
    var imgObj = new Image();
    imgObj.src = imgs[count];

    $(imgObj).on('load error', function () { // 沒錯我使用了jQuery
        console.log(count);
        if (count >= len) {
            console.log('加載完畢');
            $('.container').addClass('active');
        } else {
            load(); // 繼續加載下一張
        }

        count++;
    });
}

二、jquery代碼:(已經封裝成插件)數組

/**
 * Created by WEIWEI on 2017/10/10.
 */
(function($){
    function Preload(imgs,options){
    //    定義
        this.imgs = (typeof imgs === 'string')?[imgs]:imgs;//保證imgs爲數組
        this.opts = $.extend({},Preload.DEFAULTS,options)//用options去覆蓋默認值
    //    調用加載方法
        if(this.opts.order == "ordered"){//有序加載
            this._orderedLoad();
        }else {
            this._unOrdered();//無序加載
        }
    //    Preload的默認值
        Preload.DEFAULTS = {
            order:"ordered",//默認有序加載
            each:null,//每張圖片加載完成後調用此方法
            all:null//圖片加載完畢調用此方法
        };
    }
    //    有序加載
        Preload.prototype._orderedLoad = function(){
            var imgs = this.imgs;
            var opts = this.opts;
            var count = 0;
            var len = imgs.length;

            function load(){
                var imgObj = new Image();
                imgObj.src = imgs[count];
                $(imgObj).on("load error",function(){
                    if(count > len-1){
                        opts.all && opts.all();//所有加載完成
                    }else {
                        opts.each && opts.each(count);
                        load();
                    }
                    count ++ ;
                })
            }
            load();
        };
    //    無需加載
        Preload.prototype._unOrdered = function(){
            var imgs = this.imgs;
            var opts = this.opts;
            var count = 0; // 計數器
            var len = imgs.length;
            console.log("無序加載")
            $.each(imgs, function (index, src) {
                if (typeof src != 'string') { // src路徑不是字符串則不往下執行
                    console.error('請傳入字符串形式的圖片路徑');
                    return;
                }
                var imgObj = new Image();
                imgObj.src = src;

                $(imgObj).on('load error', function () {
                    opts.each && opts.each(count); // 首先判斷each屬性是否存在,存在則執行

                    if (count >= len -1) {
                        opts.all && opts.all(); // 同理,不過是在圖片加載完成以後調用
                    }

                    count++;
                });
            });
        };


    //     掛載到jQuery對象上
    $.extend({
        preload: function (imgs, opts) { // 命名爲preload
            new Preload(imgs, opts);
        }
    });
})(jQuery);
    <script>
        var imgs=[
            'http://pic1.win4000.com/wallpaper/9/579c3fbaa2918.jpg',
            'http://img.tuku.cn/file_big/201404/7214f32de01b4fd8b0872522ead3480b.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494524&di=9dab7ea72080994182b4e0f748c65091&imgtype=0&src=http%3A%2F%2Fimg.pconline.com.cn%2Fimages%2Fupload%2Fupc%2Ftx%2Fwallpaper%2F1501%2F13%2Fc0%2F1823997_1421130296700.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396544706&di=7b83b4ba4b6b4952a076bcb701a54d77&imgtype=jpg&src=http%3A%2F%2Fimg1.imgtn.bdimg.com%2Fit%2Fu%3D3804939088%2C891611583%26fm%3D214%26gp%3D0.jpg',
            'https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1507396494761&di=b34fdf8f57cd2df851f4a38dbea91035&imgtype=0&src=http%3A%2F%2Fpic.5442.com%2F2013%2F0504%2F02%2F10.jpg'
        ];
        $.preload(imgs, {
            order: 'unordered',
            each: function (count) {
                console.log('正在加載第' + (count + 1) + '張圖片');
            },
            all: function () {
                console.log('所有加載完成');
            }
        });
    </script>

二:懶加載(就是延時加載)瀏覽器

當圖片出如今可視化窗口以後,圖片才加載到本地。緩存

原網站(https://juejin.im/post/59cb634a6fb9a00a4843bea9)網絡

懶加載原理

<img>標籤有一個屬性是src,用來表示圖像的URL,當這個屬性的值不爲空時,瀏覽器就會根據這個值發送請求。若是沒有src屬性,就不會發送請求。

我先不設置src,須要的時候再設置?

nice,就是這樣。

咱們先不給<img>設置src,把圖片真正的URL放在另外一個屬性data-src中,在須要的時候也就是圖片進入可視區域的以前,將URL取出放到src中。

重點是 ↓,

獲取圖片是否在可視區的三個方法:

方法一

網上看到好多這種方法,稍微記錄一下。

  1. 經過document.documentElement.clientHeight獲取屏幕可視窗口高度
  2. 經過element.offsetTop獲取元素相對於文檔頂部的距離
  3. 經過document.documentElement.scrollTop獲取瀏覽器窗口頂部與文檔頂部之間的距離,也就是滾動條滾動的距離

而後判斷②-③<①是否成立,若是成立,元素就在可視區域內。

方法二 getBoundingClientRect

function isInSight(el) {
  const bound = el.getBoundingClientRect();
  const clientHeight = window.innerHeight;
  //若是隻考慮向下滾動加載
  //const clientWidth = window.innerWeight;
  return bound.top <= clientHeight + 100;
}

方法三  IntersectionObserver

先附上連接:

jjc大大:github.com/justjavac/t…

阮一峯大大:www.ruanyifeng.com/blog/2016/1…

這個方法更好,上下劃懶加載圖片更加順暢。

 

html代碼

<div class="container">
  <div class="img-area">
    <img class="my-photo" alt="loading" data-src="./img/img1.png">
  </div>
  <div class="img-area">
    <img class="my-photo" alt="loading" data-src="./img/img2.png">
  </div>
  <div class="img-area">
    <img class="my-photo" alt="loading" data-src="./img/img3.png">
  </div>
  <div class="img-area">
    <img class="my-photo" alt="loading" data-src="./img/img4.png">
  </div>
  <div class="img-area">
    <img class="my-photo" alt="loading" data-src="./img/img5.png">
  </div>
</div>

js代碼(方法三)

function checkImgs() {
  const imgs = Array.from(document.querySelectorAll(".my-photo"));
  imgs.forEach(item => io.observe(item));
}

function loadImg(el) {
  if (!el.src) {
    const source = el.dataset.src;
    el.src = source;
  }
}

const io = new IntersectionObserver(ioes => {
  ioes.forEach(ioe => {
    console.log(ioe)
    const el = ioe.target;
    const intersectionRatio = ioe.intersectionRatio;
    if (intersectionRatio > 0 && intersectionRatio <= 1) {
      loadImg(el);
    }
    el.onload = el.onerror = () => io.unobserve(el);
  });
});

源代碼:傳送門

相關文章
相關標籤/搜索