前端性能优化之图片懒加载和预加载

92 阅读2分钟

图片懒加载

什么是图片懒加载

  • 图片懒加载又叫图片延迟(按需)加载
  • 在需要的时候加载图片
  • 更好的加载页面的首屏内容 无需考虑整个页面
<!DOCTYPE html>  
<html lang="en">  
    <head>  
        <meta charset="UTF-8" />  
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />  
        <title>图片懒加载</title>  
        <style>  
            * {  
                padding: 0;  
                margin: 0;  
            }  

            img {  
                width: 100%;  
                height: 183px;  
            }  
        </style>  
    </head>  
    <body>  
        <div class="img-container">  
            <img  
                src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"  
                alt=""  
                data-src="https://gitee.com/z1725163126/cloundImg/raw/master/1.jpg"  
                class="lazyload"  
            />  
        </div>  
        <div class="img-container">  
            <img  
                src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"  
                alt=""  
                data-src="https://gitee.com/z1725163126/cloundImg/raw/master/2.jpg"  
                class="lazyload"  
            />  
        </div>  
        <div class="img-container">  
            <img  
                src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"  
                alt=""  
                data-src="https://gitee.com/z1725163126/cloundImg/raw/master/3.jpg"  
                class="lazyload"  
            />  
        </div>  
        <div class="img-container">  
            <img  
                src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"  
                alt=""  
                data-src="https://gitee.com/z1725163126/cloundImg/raw/master/4.jpg"  
                class="lazyload"  
            />  
        </div>  
        <div class="img-container">  
            <img  
                src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"  
                alt=""  
                data-src="https://gitee.com/z1725163126/cloundImg/raw/master/5.jpg"  
                class="lazyload"  
            />  
        </div>  
  
        <script>  
            // 图片要设置高度  
            const imgs = [...document.querySelectorAll(".lazyload")];  

            /** 方案一 */  
            // lazyload();  
            //  
            // window.addEventListener("scroll", lazyload, false);  
            //  
            // function lazyload() {  
            // for (let i = 0; i < imgs.length; i++) {  
            // const $img = imgs[i];  
            //  
            // if (isInVisibleArea($img)) {  
            // $img.src = $img.dataset.src;  
            // imgs.splice(i, 1);  
            // i--;  
            // }  
            // }  
            // }  
            //  
            // // DOM 元素是否在可视区域内  
            // function isInVisibleArea($el) {  
            // const rect = $el.getBoundingClientRect();  
            // // console.log(rect);  
            //  
            // return rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;  
            // }  

            /** 方案二 */  
            const observer = new IntersectionObserver(function (entries) {  
                entries.forEach(item => {  
                    if (item.target.nodeName === 'IMG' && item.isIntersecting) {  
                        // console.log(item.target.src)  
                        // console.log(item.target.dataset.src)  
                        item.target.src = item.target.dataset.src  
                        observer.unobserve(item.target)  
                    }  
                })  
            })  
            imgs.forEach(item => {  
                observer.observe(item)  
            })  
        </script>  
    </body>  
</html>

图片预加载

预加载的实际应用

  • 大图片可以预加载,可以解决图片从上往下逐渐显示的现象
  • 在这一页面的时候加载下一页,提升用户体验,比如漫画
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>图片预加载</title>
    <style>
      .img-container {
        display: flex;
        align-items: center;
        height: 100vh;
        background-color: rgba(0, 0, 0, 0.5);
      }
      img {
        width: 100%;
      }
      * {
        margin: 0;
        padding: 0;
      }
    </style>
  </head>
  <body>
    <div class="img-container">
      <img src="https://gitee.com/z1725163126/cloundImg/raw/master/1.jpg" alt="图片" id="img" />
    </div>

    <script>
      const imgs = [
        "https://gitee.com/z1725163126/cloundImg/raw/master/2.jpg",
        "https://gitee.com/z1725163126/cloundImg/raw/master/3.jpg",
        "https://gitee.com/z1725163126/cloundImg/raw/master/4.jpg",
        "https://gitee.com/z1725163126/cloundImg/raw/master/5.jpg",
      ];
      let i = 0;
      const $img = document.getElementById("img");

      // 页面一开始调用preload加载数组的第一个元素
      preload(imgs[i])
        .then((data) => {})
        .catch(() => {});

      // 点击切换
      $img.addEventListener(
        "click",
        () => {
          // 当索引小于数组length
          if (i < imgs.length) {
            // 将数组元素的src赋值给页面元素
            $img.src = imgs[i];
            // i+1 下次点击变为数组的第二个元素 依次递增
            i++;
            // 当索引小于数组length
            if (i < imgs.length) {
              // 预加载下一个图片
              preload(imgs[i]);
            }
          } else {
            // 当 索引和 数组length相同 则数组内没元素了
            console.log("已经是最后一张了!");
          }
        },
        false
      );

      // 预加载
      function preload(src) {
        // Promise进行包装
        return new Promise((resolve, reject) => {
          // 创建一个新的图片标签
          const image = new Image();

          // 图片加载完成调用成功状态
          image.addEventListener("load", () => resolve(image), false);
          // 图片加载失败调用失败状态
          image.addEventListener("error", () => reject(), false);
          // 将传进来的src赋值给新的图片
          image.src = src;
        });
      }
    </script>
  </body>
</html>