图片预加载、懒加载(延迟加载)

一:预加载:就是事先把网页的图片加载到本地,之后就直接到缓存那里拿图片了。

预加载分为有序加载和无序加载两种。

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

1、原生js实现

1)有序加载(原生js代码)

        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代码):

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++;
    });
}

2、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);
  });
});

源代码:传送门

posted @ 2017-10-11 15:30  Westbrook维  阅读(9241)  评论(0编辑  收藏  举报