loading

实现懒加载的四种方式

# 第一种

图片距离浏览器视口顶部距离 <= 浏览器视口高度 + 页面滚动距离

const imgs = document.getElementsByTagName('img');
    function lazyLoad(imgs) {
      console.log('触发了');
      // 视口的高度;
      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);
    // 设置节流函数
    function throttle(fn, delay) {
      let timer = null;
      return () => {
        if(timer) {
          return;
        };
        timer = setTimeout(() => {
          fn(imgs);
          timer = null;
        }, delay)
      }
    }
    // 监听滚动事件,加载后面的图片;
    window.onscroll = throttle(lazyLoad, 500);
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

# 第二种

Element.getBoundingClientRect() 方法返回元素的大小及其相对于视口的位置。我们可以取得它的top值,它的top值就是元素左上角到视口顶部的距离。当Element.getBoundingClientRect().top < 视口高度时触发加载;

    const imgs = document.getElementsByTagName('img');
   // 判断元素是否出现在视口内
   function isShow(el) {
     // 视口高度
     const clientH = window.innerHeight;
     const bound = el.getBoundingClientRect();
     // 判断元素左上角到视口顶部的距离是否小于视口高度
     return bound.top < clientH;
   };

   // 加载图片
   function showImg(el) {
     if(!el.src) {
       el.src = el.dataset.src;
     }
   }

   // 懒加载
   function lazyLoad() {
     console.log('加载了');
     [...imgs].forEach(el => {
       if(isShow(el)) {
         showImg(el);
       }
     })
   };

   lazyLoad();

   // 节流函数
   function throttle(fn, delay) {
     let timer = null;
     return () => {
       if(timer) {
         return;
       };
       timer = setTimeout(() => {
         fn(imgs);
         timer = null;
       }, delay);
     }
   };

   window.onscroll = throttle(lazyLoad, 500);
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
37
38
39
40
41
42
43
44

# 第三种

IntersectionObserver可以异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。也就是说它可以帮助我们去判断一个元素是否出现在视口上。这里只介绍用到的两个属性:

IntersectionObserver.observe():使IntersectionObserver开始监听一个目标元素;

isIntersecting属性:可以判断该元素是否出现在视口内;

实现思路:根据上面介绍的那两个属性,我们可以遍历每个img元素,然后监听每一个元素,最后根据isIntersecting属性去判断元素是否出现在视口内,从而决定是否让它加载。

      document.addEventListener("DOMContentLoaded", () => {
        if ("IntersectionObserver" in window) {
          const imgs = document.getElementsByTagName("img");
          const imageObserve = new IntersectionObserver((entries) => {
            entries.forEach((entry) => {
              // 通过该属性判断元素是否出现在视口内
              if (entry.isIntersecting) {
                // entry.target能够取得那个dom元素
                const data_src = ele.target.getAttribute('data-src'); //这里基本和 Method1/Method2一样
                ele.target.setAttribute('src', data_src); // ele.target 是目标元素
                // 解除监视
                imageObserve.unobserve(img);
              }
            });
          });
          [...imgs].forEach((img) => {
            // 开启监视每一个元素
            imageObserve.observe(img);
          });
        } else {
          alert("您的浏览器不支持IntersectionObserver!");
        }
      });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# 第四种

  • img 标签原生支持loading属性,可取值有:

    • eager:无论图片是否在可视区,都会直接加载图片
    • lazy:推迟图片的加载,当图片滚动到距离可视区域一定阈值(视浏览器的实现而定)的时候,再加载图片
    • auto:由浏览器自行决定
最近更新时间: 2021/08/25 17:25:09
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00