• H5页面如何实现图片懒加载?


    图片懒加载,往往作为减少首页白屏时间的一个解决方案而出现。直观的来说,就是不要直接加载所有图片,而是满足一定条件后才加载,也就是”惰性加载“。实现图片懒加载的方式有很多,如果要简单点那就直接使用第三方插件:vue-lazyload,如果想探究一下别人的插件是怎么实现图片懒加载的,那么可以看看本文是如何实现的。

    实现思路

    实现图片懒加载我们需要先明白具体的场景,一般来说,我们会在首屏先加载几张图片,其他的图片则先不加载,在页面滚动时,图片快出现在视窗中的时候才来加载图片。为什么要这么实现呢,因为对于图片很多的场景,如果一次性加载出所有的图片,可能会导致页面白屏时间比较长,特别是图片比较大的时候。

    实现过程

    1.使用data-*自定义数据属性给img标签新增一个data-src属性
    2.全局监听滚动事件,使用节流处理回调函数
    3.在回调函数中,判断图片是否已经出现在可视区域,如果已经出现在可视区域,则加载该图片
    4.页面初始化的时候执行一下回调函数,保证首屏有图片显示

    在这个实现过程中,涉及一些知识点,我们来快速回顾一下:

    准备知识

    data-*

    data-*是可自定义数据属性的属性,可用在所有的HTML元素上面,嵌入自定义的数据内容。这些自定义的数据可以在HTMMLElement.dataset中被访问到,例如:

    
    // 访问dataset
    const img = document.getElementById('img')
    console.log(img.dataset.src); // xxx.png
    console.log(img.dataset.name); // img 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    我们实现图片懒加载的最终目的,就是在恰当的时候使用data-src的值替换到src,加载真实的图片。data-*定义的数据不仅可以在js中访问,也可以在CSS中访问,具体可参考:dataset

    getBoundingClientRect()

    Element.getBoundingClientRect()方法会返回一个DOMRect对象,其包含了当前元素的大小,以及相对于视窗的位置信息。听名字可能会有点迷糊,但是结合图来看就比较好理解了:

    DOMRect对象中的widthheight是包含了元素的paddingborder-width,其位置信息指的是包含元素的最小矩形的每条边距离视窗原点(0,0)的位置。

    throttle

    由于我们会全局监听scroll滚动事件,如果每次滚动都触发回调函数的话会造成不必要的计算成本,因此我们考虑使用节流来处理滚动事件。节流的具体细节就不在此重复,我们先简单实现一个节流:

    function throttle(fn, delay = 200) {let timer = null;
      return function() {
          if (timer) return;
          timer = setTimeout(() => {
              fn.apply(this, arguments);
              timer = null;
          }, delay);
      }
    } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    window.innerHeight

    有几个很相似的”height“,我们就简单都梳理一下:

    • window.innerHeight:浏览器可视区域的高度;如果有水平滚动条,也会包含滚动条高度
    • window.outerHeight:获取整个浏览器的高度
    • Element.scrollHeight:元素内容的高度,包括由于溢出导致隐藏的内容高度
    • Element.clientHeight:元素内部的高度,包含内边距,但不包括水平滚动条、边框、外边距

    这里我们使用innerHeight即可,因为我们是在window对象上监听scroll滚动事件。

    准备工作已经完毕,接下来就直接上手代码。

    完整代码

    代码中都有相应的注释,在了解上面的准备知识后,代码就挺简单的了:

    js部分

    // 使用for循环批量创建img,html中可没有v-for可以使用
    for (let index = 0; index < 10; index++) {
      let img = document.createElement("img");
      img.src = "./loading.gif";
      img.dataset.src = "./dog.jfif"; // 由于我们是通过js创建的,因此就无法直接使用data-*,如果是在html上面,需要添加此属性
      document.body.appendChild(img);
      img = null;
    }
    // 节流
    function throttle(fn, delay = 200) {
      let timer = null;
      return function () {
          if (timer) return;
              timer = setTimeout(() => {
              fn.apply(this, arguments);
              timer = null;
          }, delay);
      };
    }
    // 懒加载-回调函数
    function lazyLoad() {
      const imgs = document.querySelectorAll('img[data-src]');
      if (!imgs.length) return;
      imgs.forEach(img => {
      const rect = img.getBoundingClientRect();
      if (rect.top < window.innerHeight) {
          img.src = img.dataset.src;
          img.removeAttribute('data-src'); // 我们是通过img[data-src]查找所有img标签的,渲染后就删除data-src可减少forEach循环的计算成本
          }
      })
    }
    // 全局监听scroll滚动事件
    window.addEventListener('scroll', throttle(() => {lazyLoad();
    }, 100));
    // 初始化的时候执行一下加载图片的函数
    lazyLoad(); 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    CSS部分

     
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    运行结果:

    首屏展示

    首先我们会默认加载三张图片,查看元素节点,这三张图片的data-src都没有,而另外没有加载的图片是有data-src的。

    滚动中展示

    滚动时会触发图片加载的回调函数,DOM树也会跟着改变

    滚动结束展示

    所有图片都将只有src,没有data-src

    总结

    本文通过监听滚动事件,在图片出现在可视区域前才加载真正的图片,如果未出现则使用默认的loading图片的方式实现了图片懒加载。一般来说,loading图片都会比较小,而实际的图片会大很,因此使用loading图片来代替是可以减少图片渲染时间的。

  • 相关阅读:
    c++ std::cout输出结果错误,只有一堆数字没有指定的字符串?
    springboot整合Redis
    计算大于2的任意正整数n以内的所有素数(质数)的和
    关于广域网与局域网介绍及数据交换
    SDUT F - 判断回文串
    MySQL大全(基础篇)
    java PipedReader类、PipedWriter类
    利用面向对象方法,处理数据文件【Python】
    开源进击未来:开放原子开源大赛苏州站获奖名单公布(4月17-18日)
    数据结构之-----二叉树
  • 原文地址:https://blog.csdn.net/weixin_53312997/article/details/126159182