zoukankan      html  css  js  c++  java
  • 原生 JS 实现图片懒加载的思路

    实现方案

    • 1. 在 img 元素时,自定义一个属性 data-src,用于存放图片的地址

    • 2. 获取屏幕可视区域的尺寸

    • 3. 获取元素到窗口边缘的距离

    • 4. 判断元素时候在可视区域内,在的话则 data-src 的值赋给 src;否则不执行其他操作

    本质上:当图片在可视区域内时才会加载否则不加载;也可以给一个默认的图片占位。

    需要的 api:

    • IntersectionObserver它提供了一种异步观察目标元素与顶级文档 viewport 的交集中的变化的方法

    • window.requestIdleCallback()方法将在浏览器的空闲时段内调用的函数排队。这使开发者能够在主事件循环上执行后台和低优先级工作,而不会影响延迟关键事件,比如动画和输入影响。

    几个注意的细节:

    • 提前加载,可以加 100px

    • 滚动时只处理未加载的图片即可

    • 函数节流

    简单代码演示

    判断是否是在可视区域的三种方式:
    
      屏幕可视区域的高度+滚动条滚动距离>元素到文档顶部的距离,即document.documentElement.clientHeight+document.documentElement.scrollTop> element.offsetTop
    
      使用getBoundingClientRect()获取元索大小和位置
    
      IetersectionObserver自动观察元素是否在视口内
    <!DOCTYPE html>
    <html lang="en">
      <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="./images/1.png" alt="" />
        <img data-src="./images/2.png" alt="" />
        <img data-src="./images/3.png" alt="" />
        <img data-src="./images/4.png" alt="" />
        <img data-src="./images/5.png" alt="" />
        <img data-src="./images/6.png" alt="" />
      </body>
      <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);
            }
          };
        }
    
        //方法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);
    
        // 方法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 () {
        //   throttleLazyLoad1(imgs);
        //   // throttleLazyLoad2(imgs);
        // };
    
        // 方法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>
    </html>

    其他相关文章:页面性能优化 - 原生JS 实现图片懒加载

  • 相关阅读:
    list()
    Python 数据类型转换
    设计模式 — 代理模式(静态代理、动态代理、Cglib代理) 转载
    java线程池实现原理
    HashMap深度解析(转载) jdk1.7
    Java Serializable 序列化和反序列化 (转载)
    Java遍历HashMap并修改(remove)(转载)
    Java中的break,continue关于标签的用法(转载)
    遍历List过程中删除操作报java.util.ConcurrentModificationException错误
    java Date时间的各种转换方式和Mysql存时间类型字段的分析
  • 原文地址:https://www.cnblogs.com/bala/p/15693360.html
Copyright © 2011-2022 走看看