一、背景介绍
在实际项目中,可能会存在大量的图片资源,如果一开始就完全加载所有的图片,可能会导致页面加载缓慢,用户体验较差。这时,可以采用一种叫做懒加载(Lazy load)的技术,具体做法是:当图片滚动至用户可视范围内时,再去加载真正的图片资源。
懒加载技术所带来的好处如下:
- 减少首屏加载资源,提高页面加载速度;
- 减轻服务器资源消耗,节省带宽流量;
- 可有效解决浏览器限制的最大并发请求数量。
本文将详细介绍前端图片懒加载技术的实现原理,以及结合实际例子实现懒加载功能。
二、实现原理
图片懒加载的关键点在于图片资源的加载时机,即,当图片出现在用户的视口范围内时,才去请求实际的图片资源。监听图片是否滚动到视口范围内,可以通过以下两种方式实现:
- 监听页面滚动事件
scroll,并结合图片相对视口的位置来判断图片是否出现在视口范围内; - 使用
IntersectionObserverAPI实现,当目标元素与父元素相交时,触发回调函数。
下面将分别介绍这两种实现方式。
2.1 监听滚动事件判断图片位置
(1)HTML结构
首先,我们需要为图片占位,并提供一个占位符(如:默认图片或者一张透明的1px*1px的图片),在图片懒加载完成之前展示。同时,我们需要将图片的真实URL保存在data-src属性中。
<img class="image-lazy" data-src="http://example.com/real/image/url" src="http://example.com/placeholder/url">
(2)JavaScript实现
首先,我们需要编写一个判断元素是否在可视范围内的函数:
function isElementInView(element) {
const rect = element.getBoundingClientRect();
return (
rect.top = (window.innerHeight || document.documentElement.clientHeight)
rect.left = (window.innerWidth || document.documentElement.clientWidth)
);
}
接下来,编写一个加载图片的函数。当判断到某个图片元素在可视范围内时,就将该图片的data-src属性赋值给src属性,同时移除data-src属性:
function loadImage(imgEl) {
const realSrc = imgEl.getAttribute("data-src");
if (realSrc) {
imgEl.src = realSrc;
imgEl.removeAttribute("data-src");
}
}
最后,我们需要监听页面滚动事件,并判断懒加载图片是否处于可视范围内:
window.addEventListener("scroll", function() {
const imgs = document.querySelectorAll(".image-lazy[data-src]");
imgs.forEach((img) => {
if (isElementInView(img)) {
loadImage(img);
}
});
});
优缺点:
优点是实现较为简单,兼容性较好;缺点是会产生性能问题,因为页面滚动时触发频率极高,产生大量重绘、重排操作。
为了解决该问题,可以使用requestAnimationFrame、setTimeout或者防抖节流优化滚动事件。这里不再赘述。
2.2 使用IntersectionObserver API实现
IntersectionObserverAPI是现代浏览器提供的一种通用的观察器模式实现,用于监听元素进入或离开另一个元素(如视口)。
(1)HTML结构
与监听滚动事件的实现方式相同,
<img class="image-lazy" data-src="http://example.com/real/image/url" src="http://example.com/placeholder/url">
(2)JavaScript实现
首先,创建一个IntersectionObserver实例:
const observer = new IntersectionObserver(function(entries) {
// 对每个相交的图片元素,处理懒加载
entries.forEach(entry => {
if (entry.isIntersecting) {
loadImage(entry.target);
// 当图片懒加载完成,取消对该图片的观察
observer.unobserve(entry.target);
}
});
}, {
rootMargin: '100px', // 兼容用户提前滚动浏览到图片的场景
threshold: 0
});
在此基础上,我们需要使用IntersectionObserver观察页面上的所有懒加载图片:
const lazyImages = document.querySelectorAll('.image-lazy');
lazyImages.forEach(img => observer.observe(img));
优缺点:
优点是性能较好,加载逻辑与滚动事件解耦,无需额外优化;但缺点是兼容性较差,需要使用polyfill解决。
三、第三方库
除了自己实现懒加载功能,还可以使用现有的成熟的第三方库,如:lazysizes、lozad等。
在实际项目中可以根据需要选择不同的技术方案。在兼容性要求不高的情况下,可以优先选择IntersectionObserverAPI实现。