什么是图像的懒加载?如何实现?

图像的懒加载是一种优化网页性能的技术,它延迟加载视口之外的图像,直到用户滚动到它们即将出现的位置时才加载。这样可以减少初始页面加载时的网络请求和数据传输量,加快首屏渲染速度,节省用户流量。

在这里插入图片描述

原理

懒加载的核心思想是:将图像的真正的URL存储在自定义属性(例如 data-src)中,而 <img>src 属性初始设置为占位图或留空。 然后通过监听滚动事件或使用更现代的 Intersection Observer API,监测图像元素是否进入视口。一旦元素进入视口,就将 data-src 的值赋给 src,触发浏览器加载真实的图像。

实现方式

1.浏览器默认支持的懒加载

MDN中图片懒加载属性的描述

使用浏览器原生 loading="lazy"(最简单),HTML5 提供了原生的图片懒加载属性

<img src="image.jpg" loading="lazy" alt="..." />
  • 优点:无需额外代码,浏览器自动处理。
  • 缺点:兼容性稍差(不支持较旧浏览器),且无法自定义加载阈值。
2. 基于事件的懒加载(传统方式)
  • 步骤
    1. 获取所有需要懒加载的图像元素(例如带有 data-src 属性的 <img>)。
    2. 监听 scrollresizeorientationchange 事件。
    3. 在事件处理函数中,遍历这些图像,通过 getBoundingClientRect() 判断其是否进入视口(例如 top < window.innerHeightbottom > 0)。
    4. 如果进入视口,则将 data-src 的值赋给 src,并将图像从待加载列表中移除或标记为已加载。
    5. 注意使用节流(throttle)优化高频事件,避免性能问题。
  • 缺点:需要手动计算位置,且滚动事件触发频繁,性能较差。
3. 基于 Intersection Observer 的懒加载(现代推荐)
  • 原理:Intersection Observer 异步观察目标元素与祖先元素或视口的交叉状态,当元素进入或离开视口时会触发回调,无需手动监听滚动事件。
  • 步骤
    1. 创建一个 Intersection Observer 实例,配置根元素(通常为 null 表示视口)和阈值(例如 threshold: 0.1 表示元素出现 10% 时触发)。
    2. 使用 observer.observe(img) 对每个待懒加载的图像开始观察。
    3. 在回调函数中,遍历所有发生交叉变化的条目(entries)。对于每个条目,如果 isIntersectingtrue(即进入视口),则加载真实图像(将 data-src 赋给 src),然后停止观察该元素(observer.unobserve(img))。
  • 优点:性能更好,代码简洁,且能自动处理动态添加的元素。
示例代码(Intersection Observer)
<img class="lazy" data-src="real-image.jpg" src="placeholder.jpg" alt="...">
const lazyImages = document.querySelectorAll('img.lazy');
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target;
      img.src = img.dataset.src;
      img.classList.remove('lazy'); // 可选:移除标记
      observer.unobserve(img);       // 停止观察
    }
  });
}, {
  rootMargin: '0px 0px 200px 0px', // 可选:提前加载(例如距离视口底部200px时触发)
  threshold: 0.01
});

lazyImages.forEach(img => observer.observe(img));
注意事项
  • 占位图:初始 src 可设置为极小占位图或 Base64 图像,避免空白闪烁。
  • 尺寸设置:为 <img> 设置明确的 widthheight 属性,或使用 CSS 预留空间,防止图像加载后造成页面布局偏移。
  • 加载失败处理:监听 error 事件,加载失败时显示默认图片。
  • 兼容性:Intersection Observer 在现代浏览器中支持良好,但如需要兼容旧版浏览器,可引入 polyfill 或回退到事件监听方式。

React项目中的使用情况

使用 Intersection Observer 自定义实现(推荐)

封装一个 LazyImage 组件,利用 Intersection Observer 监听图片是否进入视口,进入后再加载真实图片。

示例:LazyImage 组件
import React, { useEffect, useRef, useState } from 'react';

const LazyImage = ({ src, placeholder, alt, ...props }) => {
  const imgRef = useRef();
  const [loaded, setLoaded] = useState(false);

  useEffect(() => {
    const observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          if (entry.isIntersecting) {
            // 进入视口,加载真实图片
            const img = entry.target;
            img.src = src;
            setLoaded(true);
            observer.unobserve(img); // 停止观察
          }
        });
      },
      {
        rootMargin: '200px 0px', // 提前 200px 加载
        threshold: 0.01,
      }
    );

    if (imgRef.current) {
      observer.observe(imgRef.current);
    }

    // 清理 observer
    return () => {
      if (imgRef.current) {
        observer.unobserve(imgRef.current);
      }
    };
  }, [src]); // 依赖 src,当 src 变化时重新观察

  return (
    <img
      ref={imgRef}
      src={placeholder} // 初始占位图
      alt={alt}
      {...props}
    />
  );
};

export default LazyImage;
使用方式
<LazyImage
  src="real-image.jpg"
  placeholder="placeholder.jpg"
  alt="description"
/>
1.2 使用第三方库
  • react-lazyload:老牌库,基于滚动事件监听。
  • react-intersection-observer:提供 useInView Hook,简化 Intersection Observer 的使用。
  • react-lazy-load-image-component:功能丰富,支持占位、淡入效果等。

例如使用 react-intersection-observer

npm install react-intersection-observer
import { useInView } from 'react-intersection-observer';

const LazyImage = ({ src, placeholder, alt }) => {
  const { ref, inView } = useInView({
    triggerOnce: true,
    rootMargin: '200px 0px',
  });

  return (
    <img
      ref={ref}
      src={inView ? src : placeholder}
      alt={alt}
    />
  );
};

Nextjs中如何实现

Next.js 提供的 next/image 组件是图像优化的终极方案,它默认开启了懒加载

import Image from 'next/image';

export default function Page() {
  return (
    <>
      {/* 首屏大图:急切加载,高优先级 */}
      <Image src="/hero.jpg" alt="Hero" width={1200} height={600} priority loading="eager" />
      
      {/* 下方图片:默认懒加载 */}
      <Image src="/gallery/image1.jpg" alt="Gallery 1" width={800} height={600} />
    </>
  );
}

如何正确实现SEO友好的懒加载

为了充分利用懒加载的优势并规避风险,可以遵循以下最佳实践:

  • 区别对待首屏与下方内容
    • 首屏重要图片永远不要对它们使用懒加载。应使用loading="eager",并为最重要的图片(如LCP元素)加上priority属性。
    • 首屏下方的图片:放心地使用懒加载。
  • 始终设置图片尺寸:为<img>标签加上widthheight属性。这能为图片预留空间,防止懒加载导致页面布局突然变化。
  • 检查最终实现效果:如果使用了复杂的懒加载库,可以用Google Search Console的"网址检查"工具,查看Google看到的渲染后HTML,确保图片的URL正确出现在src属性中。

总结

  1. 通过懒加载,可以显著提升长页面的加载速度和用户体验,是前端性能优化的常用手段。
  2. 需要注意的是图像懒加载对SEO(搜索引擎优化)的影响是双面的。关键在于如何实现它:正确的实现是强大的优化工具,而错误的实现则可能损害你的搜索排名。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐