实现懒加载的几种方式(一)

17,433 阅读3分钟

1. 什么是懒加载?

当我们碰到长网页有很多图片时,我们会采用先加载出现在视口内的几张图片,当滚动条滚动到相应图片的位置时才去加载别的图片。这种延迟加载的方式我们就称之为懒加载。

2. 懒加载的优点

  • 提升用户体验

    假设一个场景:当我们浏览淘宝的时候,页面需要加载很长时间才能显示出来,根据3秒钟定律,此时用户肯定已经失去了耐心。但是使用懒加载就能够大大提升页面的展现速度,从而提升用户体验。

  • 减轻服务器压力

    想象一下,如果一个人需要在短时间内做很多事情,那这个人肯定压力会很大。服务器也是一样的,我们通过懒加载就减轻了服务器的工作量,让它有时间缓一缓,再来处理后面的事情。

3. 实现原理

前面铺垫了这么多,下面重点来了(敲黑板!!!)。

  • clientHeight:浏览器视口的高度;
  • scrollTop:滚动轴滚动的距离;
  • offsetTop:图片的头部距离浏览器顶部的高度(注意不是距离视口顶部的高度);

我们实现懒加载的想法是一开始只加载显示在视口内的图片,从上图可以看出,我们可以先只加载前两张图片。那么如何保证图片不加载出来呢?

可以通过将图片的地址保存在img元素的自定义属性上面,当需要加载的时候再将该自定义属性赋值给该图片的src

那么问题来了,什么时候加载后面的图片呢?

就是在我们滚动滚动轴的时候,当下一张图片的顶部马上要出现在视口的时候去加载下一张图片。

好啦,现在我们已经知道该什么去加载下一张图片了。那么接下来是第二个问题:怎么知道下一张图片马上要出现在视口上了呢?

就是当图片距离浏览器顶部的高度---即offsetTop <= 视口高度clientHeight + 滚动条的长度scrollTop这是重点!!!明白了这个后面就简单了

最后一个问题,如何获取offsetTopscrollTopclientHeight这三个数值呢?

  • offsetTop:直接通过img.offsetTop就可以获取;
  • scrollTop:通过document.documentElement.scrollTop获取;
  • clientHeight:通过document.documentElement.clientHeight获取;

此处主要介绍懒加载,对于上述三个api不熟悉可自行百度学习。建议先记住他们可以这么获取就行。

4. 代码实现

  • 首先定义html结构和CSS样式;
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    img {
      height: 450px;
      display: block;
      margin-bottom: 20px;
    }
  </style>
</head>
<body>
  <!--图片地址暂时先保存在data-src这个自定义属性上面-->
  <img data-src="./img-loop/img/1.jpg" alt="懒加载1" />
  <img data-src="./img-loop/img/2.png" alt="懒加载2" />
  <img data-src="./img-loop/img/3.jpg" alt="懒加载3" />
  <img data-src="./img-loop/img/4.jpg" alt="懒加载4" />
  <img data-src="./img-loop/img/5.jpg" alt="懒加载5" />
</body>
</html>
  • 下面编写js;
    const imgs = document.getElementsByTagName('img');
    function lazyLoad(imgs) {
      // 视口的高度;
      const clientH = document.documentElement.clientHeight;
      // 滚动的距离,这里的逻辑判断是为了做兼容性处理;
      const clientT = document.documentElement.scrollTop || document.body.scrollTop;
      for(let i = 0; i < imgs.length; i++) {
        // 逻辑判断,如果视口高度+滚动距离 > 图片到浏览器顶部的距离就去加载;
        // !imgs[i].src 是避免重复请求,可以把该条件取消试试:可以看到不加该条件的话往回滚动就会重复请求;
        if(clientH + clientT > imgs[i].offsetTop && !imgs[i].src) {
          // 使用data-xx的自定义属性可以通过dom元素的dataset.xx取得;
          imgs[i].src = imgs[i].dataset.src;
        }
      }
    };
    // 一开始能够加载显示在视口中的图片;
    lazyLoad(imgs);
    // 监听滚动事件,加载后面的图片;
    window.onscroll = () => lazyLoad(imgs);

至此,我们就完成了开头gif图的懒加载的效果。

5. 性能优化

其实上面的代码还是有很多性能优化的地方,比如说对于频繁触发的scroll事件会给浏览器造成很大的压力。我们可以使用节流函数做一个优化;

  • 没有优化前,滚动的时候lazyLoad函数频繁触发;

  • 使用节流函数进行优化;
    // 设置节流函数
    function throttle(fn, delay) {
      let timer = null;
      return () => {
        if(timer) {
          return;
        };
        timer = setTimeout(() => {
          fn(imgs);
          timer = null;
        }, delay)
      }
    }
    // 监听滚动事件,加载后面的图片;
    window.onscroll = throttle(lazyLoad, 500);
  • 优化后的效果;


完整代码

下一篇:懒加载的第二种实现方式