React中如何实现渐进增强的图片懒加载兼容旧浏览器?

ლ雨诺 阅读 49

我在用React做图片懒加载时遇到了问题,用IntersectionObserver实现的方案在IE11完全失效,基础图片都不显示了。我试过在组件里这样写:


function LazyImage({ src }) {
  const imgRef = useRef();
  useEffect(() => {
    const observer = new IntersectionObserver(entries => {
      if (entries[0].isIntersecting) {
        imgRef.current.src = src;
        observer.unobserve(imgRef.current);
      }
    });
    observer.observe(imgRef.current);
    return () => observer.disconnect();
  }, []);
  return <img ref={imgRef} src="" />;
}

但这样写的话,旧浏览器连基础的占位图都不会显示,用户会看到大片空白。我应该怎么在保持现代实现的同时,确保基础体验?有没有优雅的回退方案?

我来解答 赞 11 收藏
二维码
手机扫码查看
2 条解答
西门阳阳
啊这个问题我也踩过坑!IE11真的是前端开发的快乐源泉(苦笑)。我的做法是先检查浏览器是否支持IntersectionObserver,不支持的话直接加载图片,支持的话才用懒加载。

具体代码可以这样改:

function LazyImage({ src, placeholder }) {
const imgRef = useRef();

useEffect(() => {
if (!('IntersectionObserver' in window)) {
// 旧浏览器直接加载图片
imgRef.current.src = src;
return;
}

const observer = new IntersectionObserver(entries => {
if (entries[0].isIntersecting) {
imgRef.current.src = src;
observer.unobserve(imgRef.current);
}
});
observer.observe(imgRef.current);
return () => observer.disconnect();
}, [src]);

// 给个默认占位图
return <img ref={imgRef} src={placeholder || "data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='100' height='100'%3E%3C/svg%3E"} />;
}


几个关键点:
1. 增加了placeholder属性,让调用方可以自定义占位图
2. 检查window.IntersectionObserver存在性
3. 兜底方案是直接加载图片
4. 给了个极小的base64占位图默认值

这样现代浏览器用懒加载,旧浏览器至少能看到图片,虽然没懒加载效果但不会空白。顺便说下,这个base64占位图是我偷懒用的,实际项目你可能会想用更好的占位图方案。
点赞
2026-03-08 17:20
技术岳阳
你这个写法在不支持 IntersectionObserver 的浏览器里确实会出问题,因为 JS 里面直接走了 observe 流程,但旧浏览器压根没有这个 API,而且你初始 src 是空的,连占位图都没有,用户当然看到一片空白。

正确的做法是做渐进增强:先保证基础 HTML 能显示一个默认图或者低清图,再用 JS 增强加载高清图。同时对不支持 IntersectionObserver 的环境做降级,比如直接加载图片或者用 scroll 事件模拟。

你可以这样改:

function LazyImage({ src, fallbackSrc = '/placeholder.jpg' }) {
const imgRef = useRef();

useEffect(() => {
// 检查是否支持 IntersectionObserver
if (!('IntersectionObserver' in window)) {
// 不支持就直接加载真实图片
imgRef.current.src = src;
return;
}

const observer = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
imgRef.current.src = src;
observer.unobserve(imgRef.current);
}
});

observer.observe(imgRef.current);

return () => observer.disconnect();
}, [src]);

return ;
}


关键点:

1. 给 img 一个 fallbackSrc 作为初始 src,确保即使 JS 不执行或者报错,也能显示一张占位图
2. 加个 loading="lazy",现代浏览器原生懒加载会接管,算是双重保障
3. JS 里面先判断有没有 IntersectionObserver,没有就直接赋值 src,别走 observe 流程
4. 如果你真要兼容 IE11,记得 polyfill 或者用定时检测位置的方式回退,但一般项目到这一步就够了

这样写,老浏览器至少能看到占位图,不会白屏,新浏览器该懒加载懒加载,体验也更好。
点赞 9
2026-02-12 13:00