js实现懒加载图片
实现懒加载图片的基本原理
懒加载(Lazy Loading)是一种延迟加载非关键资源的技术,对于图片来说,只有当图片进入或即将进入视口(viewport)时才加载,从而减少初始页面加载时间和带宽消耗。
Intersection Observer API 实现
现代浏览器支持IntersectionObserver API,可以高效监听元素是否进入视口。
document.addEventListener('DOMContentLoaded', function() {
const lazyImages = [].slice.call(document.querySelectorAll('img.lazy'));
if ('IntersectionObserver' in window) {
const lazyImageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(function(entry) {
if (entry.isIntersecting) {
const lazyImage = entry.target;
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove('lazy');
lazyImageObserver.unobserve(lazyImage);
}
});
});
lazyImages.forEach(function(lazyImage) {
lazyImageObserver.observe(lazyImage);
});
}
});
HTML 结构示例:

<img class="lazy" data-src="image.jpg" alt="Lazy loaded image">
兼容旧浏览器的实现方式
对于不支持IntersectionObserver的浏览器,可以使用滚动事件监听结合getBoundingClientRect。
function lazyLoad() {
const lazyImages = [].slice.call(document.querySelectorAll('img.lazy'));
if ('IntersectionObserver' in window) {
// 使用 IntersectionObserver
} else {
lazyImages.forEach(function(lazyImage) {
if (isInViewport(lazyImage)) {
lazyImage.src = lazyImage.dataset.src;
lazyImage.classList.remove('lazy');
}
});
}
}
function isInViewport(element) {
const rect = element.getBoundingClientRect();
return (
rect.bottom >= 0 &&
rect.right >= 0 &&
rect.top <= (window.innerHeight || document.documentElement.clientHeight) &&
rect.left <= (window.innerWidth || document.documentElement.clientWidth)
);
}
// 初始加载
document.addEventListener('DOMContentLoaded', lazyLoad);
// 滚动时加载
window.addEventListener('scroll', lazyLoad);
window.addEventListener('resize', lazyLoad);
使用 loading="lazy" 原生属性
现代浏览器已支持原生懒加载,只需添加loading="lazy"属性。

<img src="image.jpg" loading="lazy" alt="Lazy loaded image">
性能优化建议
- 为懒加载图片设置占位图或背景色,避免布局抖动
- 使用
width和height属性固定图片尺寸 - 考虑预加载即将进入视口的图片(提前100-300px)
- 对动态加载的内容(如无限滚动)需要重新监听新图片
框架实现示例(Vue.js)
在Vue中可以通过自定义指令实现懒加载:
Vue.directive('lazy', {
inserted: function(el) {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
el.src = el.dataset.src;
observer.unobserve(el);
}
});
});
observer.observe(el);
}
});
使用方式:
<img v-lazy data-src="image.jpg" alt="Lazy loaded image">






