• 24小时服务热线:400-088-1128

当前位置 南顺网络>> 知识拓展

实现基本的图片懒加载

原理

先不给图片设置 src属性值, 当图片进入浏览器窗口的时,给图片的src属性赋值, 开始请求图片并渲染至屏幕。

方案

  • 给将每张图片加上一个data-src属性来保存正确的图片链接,将src属性设置为空(或默认图片链接)
  • 将所有需要延迟加载的图片用一个盒子包起来,设置宽高和默认的占位符,把原来的位置撑起来
  • 等到其他资源都加载完成之后,观察图片是否在视窗之内,决定是否开始加载图片,即是否给src属性赋予正确的值
  • 对于图片数量很多的情况,需要在页面滚动的时候判断是否需要对图片进行加载,在当前图片区域完全展示出来后再加载真实图片,即包裹图片的盒子底部出现在视窗之内时开始加载图片

  • 方案图示:

    现在有一个需要解决的问题:怎么知道图片是否在视窗之内呢?

    可以这样判断:当图片的底部和页面的顶部的距离小于视窗的底部和页面的顶部的距离时就可以认为图片已经进入视窗了。这样说起来有些绕,用图片来看看会更清晰。

    当视窗在下拉过程中其底部低于图片的底部时,就认为图片已经要加载了:




    代码实现

    实现单张图片的懒加载

    为方便说明,先实现单张图片的懒加载,使用 JQuery库来完成。

    JQuery的api中可以获取到视窗的高度、视窗顶部和页面顶部的距离,二者相加就是视窗底部和页面顶部的距离;同样的,也可以获得图片包裹层的高度和它的顶部到页面顶部的距离,相加就是图片包裹层底部到页面顶部的距离。

    DOM 结构
    <div class="wrap-single"> <img src="" data- src="http://img1.imgtn.bdimg.com/it/u=461406802,1565444607&fm=26&gp=0.jpg"> div>

    图片初始样式
    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 Demoh1>
          <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. 本文仅实现懒加载的基本代码,在现实应用中还有许多待改进的地方。