美文网首页
笔记 - 图片的加载 & 懒加载

笔记 - 图片的加载 & 懒加载

作者: 青城墨阕 | 来源:发表于2021-08-13 17:20 被阅读0次
    实现图片的加载
    function createImg(url, delay) {
        return new Promise((resolve, reject) => {
            const img = new Image();
            img.src = url;
            setTimeout(() => {
                document.body.appendChild(img);
                resolve();
            }, delay);
        });
    }
    
    createImg('https://img2.baidu.com/it/u=575711754,3157460132&fm=26&fmt=auto&gp=0.jpg', 2000)
        .then(() => {
            createImg('https://img2.baidu.com/it/u=2597283190,2423487059&fm=26&fmt=auto&gp=0.jpg', 4000);
        })
        .then(() => {
            createImg('https://img2.baidu.com/it/u=602619791,1793937306&fm=26&fmt=auto&gp=0.jpg', 6000);
        });
    
    image.png
    图片的懒加载
    • 实现方案:
      1. 在img标签内自定义一个属性data-src,用于暂存图片地址
      2. 获取屏幕可视区域的尺寸
      3. 获取当前图片上边距到窗口的距离
      4. 判断当前元素在可视区域内,则将data-src的value赋值给src。否则,不执行任何操作。
    • 细节

      1. 提前加载,可以+100像素
      2. 滚动时只处理未加载的图片
      3. 利用数据节流兼顾性能
    • 判断是否在可视区域的三种方式:

      1. 屏幕可是区域的高度 + 滚动条滚动的距离 > 元素到文档顶部的距离
        (document.documentElement.clientHeight + document.documentElement.scrollTop > element.offsetTop)
      2. 使用getBoundingClientRect()获取元素大小和相对于视口的位置(各个浏览器都支持)
      3. IntersectionObserver提供了一种异步观察目标元素与其祖先元素或顶级文档视窗(viewport)交叉状态的方法。祖先元素与视窗(viewport)被称为根(root)(各浏览器兼容性较差)
    • HTML代码

    <head>
      <meta charset="UTF-8" />
      <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      <meta http-equiv="X-UA-Compatible" content="ie=edge" />
      <title>图片懒加载</title>
      <style>
        img {
          display: block;
          height: 450px;
          margin-bottom: 20px;
        }
      </style>
    </head>
    
    <body>
      <img data-src="https://img2.baidu.com/it/u=575711754,3157460132&fm=26&fmt=auto&gp=0.jpg" alt="" />
      <img data-src="https://img2.baidu.com/it/u=2597283190,2423487059&fm=26&fmt=auto&gp=0.jpg" alt="" />
      <img data-src="https://img2.baidu.com/it/u=602619791,1793937306&fm=26&fmt=auto&gp=0.jpg" alt="" />
      <img data-src="https://img0.baidu.com/it/u=1897263140,1647399841&fm=26&fmt=auto&gp=0.jpg" alt="" />
      <img data-src="https://img2.baidu.com/it/u=2787125542,2636933450&fm=26&fmt=auto&gp=0.jpg" alt="" />
      <img data-src="https://img2.baidu.com/it/u=3200334446,1487314372&fm=26&fmt=auto&gp=0.jpg" alt="" />
    </body>
    
    • JS - 获取所有img及节流
    <script>
      var imgs = document.querySelectorAll("img");
    
      // 节流函数,定时器版本
      function throttle(func, wait) {
        let timer = null;
        return function (...args) {
          if (!timer) {
            func(...args);
            timer = setTimeout(() => {
              timer = null;
            }, wait);
          }
        };
      }
    </script>
    
    • JS - 方法1
    <script>
      //方法1: H + S > offsetTop
      function lazyLoad1(imgs) {
        //offsetTop是元素与offsetParent的距离,循环获取直到页面顶部
        function getTop(e) {
          var T = e.offsetTop;
          while ((e = e.offsetParent)) {
            T += e.offsetTop;
          }
          return T;
        }
        var H = document.documentElement.clientHeight; //获取可视区域高度
        var S = document.documentElement.scrollTop || document.body.scrollTop;
        Array.from(imgs).forEach(function (img) {
          // +100 提前100个像素就开始加载
          // 并且只处理没有src即没有加载过的图片
          if (H + S + 100 > getTop(img) && !img.src) {
            img.src = img.dataset.src;
          }
        });
      }
      const throttleLazyLoad1 = throttle(lazyLoad1, 200);
      // 滚轮事件监听
      window.onload = window.onscroll = function () {
        throttleLazyLoad1(imgs);
      };
    </script>
    
    • JS - 方法2
    <script>
    // 方法2:el.getBoundingClientRect().top <= window.innerHeight
      function lazyLoad2(imgs) {
        function isIn(el) {
          var bound = el.getBoundingClientRect();
          var clientHeight = window.innerHeight;
          return bound.top <= clientHeight + 100;
        }
        Array.from(imgs).forEach(function (img) {
          if (isIn(img) && !img.src) {
            img.src = img.dataset.src;
          }
        });
      }
      const throttleLazyLoad2 = throttle(lazyLoad2, 200);
    
      // 滚轮事件监听
      window.onload = window.onscroll = function () {
        throttleLazyLoad2(imgs);
      };
    </script>
    
    • JS - 方法3
    <script>
    // 方法3:IntersectionObserver
      function lazyLoad3(imgs) {
        const io = new IntersectionObserver((ioes) => {
          ioes.forEach((ioe) => {
            const img = ioe.target;
            const intersectionRatio = ioe.intersectionRatio;
            if (intersectionRatio > 0 && intersectionRatio <= 1) {
              if (!img.src) {
                img.src = img.dataset.src;
              }
            }
            img.onload = img.onerror = () => io.unobserve(img);
          });
        });
        imgs.forEach((img) => io.observe(img));
      }
      lazyLoad3(imgs);
    </script>
    
    只加载两张图片
    提前100像素加载图片

    相关文章

      网友评论

          本文标题:笔记 - 图片的加载 & 懒加载

          本文链接:https://www.haomeiwen.com/subject/pqzdbltx.html