本文主要是在阅读红宝书时,里面提到了 IntersectionObserver 可以实现图片懒加载,所以就想自己实现一下。

之前了解到的主要还是监听 scroll 事件,调用 getBoundingClientRect 方法来判断图片是否进入到视口

而 IntersectionObserver 它提供了一种异步观察目标元素与其祖先元素或顶级文档视口交叉状态变化的方法,它的性能也远超传统的 scroll 事件监听

# 使用 IntersectionObserver 实现图片懒加载

# 第一步:准备 HTML

核心是,不直接在 img 标签上添加 src 属性,而是添加一个自定义属性,例如 data-src

<!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>
    .image-container {
      width: 80%;
      margin: 0 auto;
    }
    img {
      display: block;
      width: 100%;
      height: 400px;
      margin-bottom: 20px;
      background-color: #f0f0f0;
    }
  </style>
</head>
<body>
  <div class="image-container">
    <img data-src="https://api.dicebear.com/9.x/adventurer/svg?seed=Alexander">
    <img data-src="https://api.dicebear.com/9.x/adventurer/svg?seed=Brian">
    <img data-src="https://api.dicebear.com/9.x/adventurer/svg?seed=Luis">
    <img data-src="https://api.dicebear.com/9.x/adventurer/svg?seed=Jack">
    <img data-src="https://api.dicebear.com/9.x/adventurer/svg?seed=Mason">
  </div>
  <script>
    // 编写逻辑
  </script>
</body>
</html>

# 第二步:编写 JavaScript 逻辑

  1. 选取所有需要懒加载的图片
  2. 创建 IntersectionObserver 实例:接收一个回调函数,当目标元素发生可见性变化时,这个回调函数就会被执行
  3. 在回调函数中处理逻辑:
    • 遍历触发变化的 entries
    • 检查 entry.isIntersecting 是否为 true ,如果是,说明图片进入到视口,需要加载图片
    • 加载图片:将 data-src 属性的值赋值给 src 属性
    • 关键:图片加载后,调用 observer.unobserve(entry.target) 方法,停止观察该图片,避免重复加载
  4. 让观察者开始工作:调用 observer.observe(target) 方法,开始观察目标元素
// 1. 选取所有需要懒加载的图片
const images = document.querySelectorAll('img[data-src]');
const lazyLoad = (target) => {
  // 2. 创建 IntersectionObserver 实例
  const io = new IntersectionObserver((entries, observer) => {
    // 3. 遍历 entries
    entries.forEach(entry => {
      if (entry.isIntersecting) {
        const img = entry.target;
        const src = img.getAttribute('data-src');
        // 4. 加载图片
        img.setAttribute('src', src);
        // 5. 图片加载后,移除 data-src 属性
        img.removeAttribute('data-src');
        // 6. 图片加载后,停止观察该图片
        observer.unobserve(img);
      }
    })
  }, {
    threshold: 0.5,
  });
  io.observe(target);
}
// 7. 遍历所有图片,调用 lazyLoad 函数
images.forEach(lazyLoad);

# 总结

HTML:使用 data-src 属性来存储图片的真实地址
JavaScript:使用 IntersectionObserver 监视图片
逻辑:当图片 isIntersecting (进入视口)时,将 data-src 替换为 src
性能:加载后 unobserve (停止观察),避免不必要的性能开销