IntersectionObserver 必须传入回调函数,root 默认为 null(视口),推荐设置 rootMargin='100px' 预加载;需校验 data-src 非空并监听 load/error;仅监听 .lazy 图片;SPA 中需在组件卸载时调用 disconnect() 避免内存泄漏。

IntersectionObserver 构造函数的必要参数和选项
必须传入一个回调函数,且 root 默认为 null(即视口),不能省略或设为 undefined。常见错误是直接写 new IntersectionObserver(callback) 却没处理 rootMargin,导致图片在进入视口瞬间才触发加载,用户已看到空白占位符。
推荐初始化时加上预加载缓冲:
const io = new IntersectionObserver(
(entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
loadImg(entry.target);
io.unobserve(entry.target);
}
});
},
{ rootMargin: '100px' } // 提前 100px 触发加载
);
-
rootMargin值支持 CSS margin 语法(如'50px 0px'),负值会缩小检测区域,慎用 - 不设置
threshold时默认为[0],意味着只要任意像素可见就触发;若想等图片 30% 进入再加载,设为[0.3] - IE 完全不支持,需用
if ('IntersectionObserver' in window)包裹,否则直接报ReferenceError
如何安全地从 data-src 切换到 src
不能直接赋值 img.src = img.dataset.src 后就认为完成——如果此时 dataset.src 是空字符串、相对路径错误,或跨域资源被拒绝,img 会变成 broken 状态,且 load 事件不会触发。
正确做法是监听 load 和 error,并提供 fallback 处理:
function loadImg(img) {
const src = img.dataset.src;
if (!src) return;
img.src = src;
img.onload = () => img.classList.add('loaded');
img.onerror = () => {
img.classList.add('failed');
img.src = '/placeholder-fail.jpg'; // 可选降级图
};
}
- 务必在设置
src前校验dataset.src存在且非空,避免触发无意义请求 - 不要依赖
img.naturalWidth > 0判断是否加载成功,它在onload前可能为 0,在onerror后仍可能为 0 - 切换后建议移除
data-src,防止重复加载或干扰后续逻辑
批量监听前需统一标记和过滤
页面中并非所有 都该懒加载:图标、关键首屏图、srcset 已优化的响应式图,都应跳过。靠 class 名过滤最可控,比如只监听带 class="lazy" 的图片。
实操时注意 DOM 就绪时机:
document.addEventListener('DOMContentLoaded', () => {
const lazyImgs = document.querySelectorAll('img.lazy');
lazyImgs.forEach(img => io.observe(img));
});
- 不要用
document.images全量遍历,它包含所有(含未加lazy的),易误伤 - 服务端渲染(SSR)场景下,可能 DOM 已存在但 JS 还未执行,此时
querySelectorAll能立即拿到节点,无需额外等待 - 动态插入的图片(如 AJAX 加载内容)需手动调用
io.observe(newImg),否则不会被监听
销毁观察器和内存泄漏风险
页面长期运行(如 SPA)时,如果路由切换后旧页面的图片仍被 IntersectionObserver 持有引用,会导致内存无法释放。不是所有场景都需要销毁,但以下情况必须主动清理:
- 组件卸载(React/Vue 中的
useEffect cleanup或beforeUnmount) - 单页应用中用户离开当前路由,且该页图片不再需要监听
- 观察目标全部加载完毕,且确认不会再新增
销毁方法很简单,但容易被忽略:
// 停止监听所有目标 io.disconnect(); // 或只停止监听某一个 io.unobserve(img);
重点:调用 disconnect() 后不能再调用 observe(),如需恢复,必须新建实例。真正难处理的是“什么时候该断开”——很多项目只在页面卸载时断开,却忘了异步加载的内容也可能长期持有 observer 实例。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











