

新闻资讯
技术学院IntersectionObserver 是懒加载唯一推荐方案,它原生支持、不阻塞主线程、自动处理边界情况;SPA中需对新节点重新 observe,且必须在真正需要时才设置 img.src 以避免重复请求。
IntersectionObserver
不用监听 scroll 事件手动计算元素位置,现代浏览器原生支持的 IntersectionObserver 是唯一推荐方案。它在元素进入视口时触发回调,不阻塞主线程,且能自动处理滚动、缩放、iframe 内嵌等边界情况。
常见错误是 fallback 到 getBoundingClientRect() + scroll 监听 —— 这会导致频繁重排重绘,尤其在低端安卓机上卡顿明显。只有需要兼容 IE 或极老 Android(
rootMargin 设为 "100px" 可提前 100px 加载,避免用户快速滚动时出现空白threshold 设过小的值(如 0.01),会增加触发频率;一般 [0, 0.1, 0.5] 足够覆盖多数场景IntersectionObserver
loading="lazy" 和占位策略loading="lazy" 是 HTML 原生懒加载属性,对 和 有效,但仅适用于常规图片请求(不支持背景图、CSS 雪碧图等)。它和 JS 懒加载不是互斥关系,而是互补:原生属性由浏览器控制,JS 方案负责兜底和精细控制。
没设置占位符直接留空 src,会导致布局抖动(layout shift)。正确做法是:
data-src 存真实地址,src 设为 1×1 透明 base64 占位图:"data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
opacity: 0,成功后用 CSS 过渡淡入,避免突兀出现img.addEventListener("error", () => img.src = "/fallback.jpg")
IntersectionObserver 在单页应用(SPA)中要重新 observe 新渲染的节点Vue/React 等框架动态插入 DOM 后,IntersectionObserver 不会自动跟踪新节点。常见错误是只在页面初始化时调用一次 observer.observe(),后续路由切换或列表刷新后新图片完全不触发加载。
解决方式取决于框架机制:
useEffect 里对每次渲染的新 ref 调用 observer.observe(el),卸载时调用 observer.unobserve(el)
onMounted + onBeforeUnmount 同理;若用 v-for 渲染列表,确保每个 都有独立 ref 或使用 querySelectorAll 批量 observeMutationObserver 捕获新增的 img[data-src] 节点,再交给 IntersectionObserver 管理const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
img.classList.remove("lazy");
observer.unobserve(img); // 加载完立即解绑,避免重复触发
}
});
}, {
rootMargin: "100px",
threshold: [0, 0.1]
});
document.querySelectorAll("img[data-src]").forEach(img => observer.observe(img));
真正容易被忽略的是资源加载顺序与缓存协同:懒加载图片的 src 设置时机,会影响浏览器是否复用已缓存的资源。如果先设 src 再加 class 控制样式,可能触发两次请求;必须确保只在需要时才写
入 src 属性。