IntersectionObserver 是现代浏览器中实现懒加载最轻量可靠的方式,不依赖 scroll 事件,通过 rootMargin 提前加载防闪动,需复用实例、及时 unobserve,并注意兼容性与 DOM 状态。
IntersectionObserver 懒加载
现代浏览器中,IntersectionObserver 是实现图片/组件懒加载最轻量、最可靠的方式。它不依赖 scroll 事件监听,避免频繁重排重绘和性能抖动,比手动计算 getBoundingClientRect() + scroll 更稳定。
典型适用
场景:长列表中的图片、折叠面板里的富媒体内容、无限滚动的卡片流。
IE 完全不支持,Edge 15+、Chrome 51+、Safari 12.1+ 均可用;如需兼容旧版 IE,必须降级为 scroll + throttle 方案rootMargin 很关键——比如设为 "200px" 表示元素进入视口前 200px 就触发加载,可避免用户滚动过快时出现“白屏闪动”IntersectionObserver
IntersectionObserver 加载图片核心逻辑是:先给 的 src 留空或设为占位图,把真实地址存在 data-src;等进入视口后,再把 data-src 赋给 src,并停止观察该元素。
const lazyImageObserver = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
const src = img.dataset.src;
if (src) {
img.src = src;
img.removeAttribute('data-src');
lazyImageObserver.unobserve(img); // 关键:及时停止观察
}
}
});
}, {
rootMargin: '200px' // 提前加载,防滚动卡顿
});
document.querySelectorAll('img[data-src]').forEach(img => {
lazyImageObserver.observe(img);
});
img.removeAttribute('data-src') 不仅是清理,也防止重复触发加载(某些情况下 isIntersecting 可能短暂为 false 后又变 true)onerror 回退逻辑,例如显示默认占位图或记录错误HTTP/2 或使用 srcset + sizes 配合懒加载,能进一步减少首屏带宽消耗能,但效果取决于使用方式和页面结构。不是所有场景都值得加懒加载,盲目使用反而引入额外 JS 开销和复杂度。
不会触发解码和纹理上传,对低端设备或 WebView 场景很关键src(否则爬虫看不到图片)这类问题基本都出在观察器配置或 DOM 状态上,不是代码逻辑 bug。
root 默认是浏览器视口,但如果父容器设置了 overflow: hidden 且有滚动,而你又没显式传 { root: container },那永远触发不了回调img 元素初始 height 为 0(比如没设宽高、父容器未渲染完成),会导致 IntersectionObserver 认为它“不可见”,即使位置正确也不触发observe();直接批量 querySelectorAll 会漏掉后来的节点transform 会让元素脱离文档流,影响 isIntersecting 判断,可临时加 will-change: transform 或改用 opacity 动画规避