图片懒加载
- 基本思路
初始渲染时不加载真实图片
把 img 标签的 src 换成一张占位图(小的 base64 或默认图片)
把真实地址存到自定义属性,比如 data-src
检测图片是否进入视口
当图片即将出现在视口(可视范围)时,替换 src 为真实图片地址
加载完成后可加渐隐动画(可选)
2. IntersectionObserver 实现(推荐)
<img data-src="https://example.com/real.jpg" alt="lazy" class="lazy" />
<img data-src="https://example.com/real2.jpg" alt="lazy" class="lazy" />
<script>
const imgs = document.querySelectorAll('img.lazy');
// 创建观察器
const observer = new IntersectionObserver((entries, obs) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 替换为真实地址
img.classList.remove('lazy');
obs.unobserve(img); // 加载一次后取消监听
}
});
}, {
root: null, // 视口
threshold: 0.1 // 进入10%就触发
});
// 绑定观察器
imgs.forEach(img => observer.observe(img));
</script>
优点:
> 性能好(浏览器原生优化)
> 代码简洁
> 不用自己计算滚动位置
3. 滚动事件 + getBoundingClientRect 实现(兼容性好)
<img data-src="https://example.com/real.jpg" alt="lazy" class="lazy" />
<img data-src="https://example.com/real2.jpg" alt="lazy" class="lazy" />
<script>
function lazyLoad() {
const imgs = document.querySelectorAll('img.lazy');
const viewHeight = window.innerHeight;
imgs.forEach(img => {
const rect = img.getBoundingClientRect();
if (rect.top < viewHeight && rect.bottom > 0) {
img.src = img.dataset.src;
img.classList.remove('lazy');
}
});
}
// 初始和滚动时调用
window.addEventListener('scroll', lazyLoad);
window.addEventListener('resize', lazyLoad);
lazyLoad();
</script>
缺点: 滚动时频繁触发,需要结合 throttle 防抖优化
手动计算元素位置
- 额外优化点 占位图:可用 1x1 base64 或 CSS 背景图 渐进式加载:先加载低清图,再替换高清图 提前加载:可以在进入视口前 100~200px 触发 SSR/SEO:如果是对搜索引擎友好的站点,要考虑服务端渲染补全图片