【短文】手写实现基本的图片懒加载

文章代码可在这里下载.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. 本文仅实现懒加载的基本代码,在现实应用中还有许多待改进的地方。

若有错误,敬请指出,谢谢~

相关文章
相关标签/搜索