什么是图片懒加载?
图片懒加载(Lazy Loading)是一种前端性能优化技术,它能让图片在 进入视口时才开始加载 ,而非页面初始时全部加载。这就像餐厅的"按需上菜",避免了一开始就把所有菜品(图片资源)都端上桌(浏览器请求)造成的资源浪费。
在电商网站、图片画廊等场景中,一个页面可能包含几十甚至上百张图片。如果不做优化,浏览器会在页面加载时同时请求所有图片资源,导致:
- 首屏加载缓慢,用户需要等待更长时间
- 浪费带宽,尤其对移动用户不友好
- 增加服务器负载,并发请求过多
中明确指出:"
img太多会严重影响页面的打开速度",而懒加载正是解决这个问题的关键方案。
懒加载的实现原理
核心思路
牛马图片的内心独白 : "上班(页面加载)先摸鱼(不加载),老板(用户)走到面前(进入视口)再假装工作(开始加载)"
- 初始摸鱼状态 :图片的真实地址不放在
src属性中,而是藏在自定义属性(如data-original)里摸鱼 - 占位表演 :
src属性使用极小的占位图或透明像素假装在工作 - 老板巡视监听 :检测图片元素是否进入视口(老板是否过来巡视)
- 被迫营业 :当图片进入视口时,才把
data-original的值赋给src属性开始加载
<img class="image-item" lazyload="true" src="https://static.360buyimg.com/item/main/1.0.12/css/i/loading.gif" data-original="https://img.36krcdn.com/hsossms/20250313/v2_15ad8ef9eca34830b4a2e081bbc7f57a@000000_oswg172644oswg1536oswg722_img_000?x-oss-process=image/resize,m_mfit,w_960,h_400,limit_0/crop,w_960,h_400,g_center" />
<img class="image-item" lazyload="true" src="https://static.360buyimg.com/item/main/1.0.12/css/i/loading.gif" data-original="https://img.36krcdn.com/hsossms/20250312/v2_aeaa7a1d51e74c3a8f909c96cd73a687@000000_oswg169950oswg1440oswg600_img_jpeg?x-oss-process=image/format,webp" />
关键技术点
- 视口检测 :判断元素是否可见(老板有没有看到)
- 资源加载 :动态设置图片地址(被迫开始工作)
- 摸鱼优化 :避免频繁触发检测逻辑(别老盯着我看)
两种实现方案对比
方案一:传统滚动监听 + 位置计算
这是最经典的实现方式,通过监听 scroll 事件,结合 getBoundingClientRect() 方法判断元素位置。就像牛马人每隔5分钟抬头看看老板来了没有,效率低但兼容性好。
<script>
const viewHeight = document.documentElement.clientHeight; // 视口高度(老板视线范围)
const eles = document.querySelectorAll('img[data-original][lazyload]'); // 所有摸鱼图片
const lazyload = function() {
// 遍历所有需要懒加载的图片(检查每个牛马的工作状态)
Array.prototype.forEach.call(eles, function(item) {
// 如果没有原始地址,则跳过(已经被抓包的不用管)
if(item.dataset.original === "") return;
// 获取元素位置信息(牛马离老板的距离)
const rect = item.getBoundingClientRect();
// 当元素进入视口(老板看到了)
if(rect.bottom >= 0 && rect.top < viewHeight) {
// 创建新图片对象(准备工作)
const img = new Image();
img.src = item.dataset.original; // 开始加载真实图片
img.onload = function() {
// 加载完成后替换占位图(开始工作)
item.src = item.dataset.original;
// 移除标记属性(已经被抓包,不用再检查)
item.removeAttribute('data-original');
item.removeAttribute('lazyload');
};
}
});
};
// 监听滚动事件(老板随时可能巡视)
window.addEventListener('scroll', lazyload);
// 初始页面加载时检查一次
document.addEventListener('DOMContentLoaded', lazyload);
</script>
牛马评价:
"这种方式就像手动打卡,每隔几秒就要抬头看老板,累得要死还容易漏看(频繁触发 scroll 事件导致性能问题)"
方案二:IntersectionObserver 智能监听
HTML5 新增的 IntersectionObserver API 可以自动监听元素是否进入视口,就像给每个牛马配了个智能打卡机,老板来了自动提醒,效率大大提升!
现代实现代码(可替换原有 scroll 监听方案):
<script>
// 创建观察者实例(智能打卡机)
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) { // 当元素进入视口(老板进入视线)
const img = entry.target;
const src = img.dataset.original;
if (src) {
img.src = src; // 加载图片(开始工作)
img.onload = function() {
img.classList.add('loaded');
img.removeAttribute('data-original');
img.removeAttribute('lazyload');
};
observer.unobserve(img); // 停止观察(打完卡就下班)
}
}
});
}, {
rootMargin: '0px 0px 200px 0px', // 提前200px开始加载(提前准备好工作)
threshold: 0.1
});
// 获取所有需要懒加载的图片并观察(给每个牛马配打卡机)
document.querySelectorAll('img[data-original][lazyload]').forEach(img => {
observer.observe(img);
});
</script>
牛马评价:
"这个好!配了智能打卡机(IntersectionObserver),我可以安心摸鱼,老板快来了会自动提醒,再也不用频繁抬头看了!"
懒加载总结
牛马人终极建议 :现代项目直接用 IntersectionObserver,配个 polyfill 兼容旧浏览器,摸鱼效率最大化!
结语
图片懒加载就像牛马人的摸鱼哲学: 不该干的活不主动干,该干的活不拖延 。合理使用懒加载技术,既能提升页面性能,又能减少资源浪费,何乐而不为呢?
最后用一句话共勉:"前端优化就像挤牙膏,多一点耐心,就能挤出更多性能(摸鱼时间)"。