导读
图片懒加载(Lazy Loading)是一种优化网页加载性能的技术,通过延迟加载那些用户暂时看不到的图片,减少初始页面加载的资源开销,提升页面的渲染速度。本文将带你了解如何使用 JavaScript 实现图片懒加载的方法,并探讨不同方法的优缺点。
什么是图片懒加载?
懒加载是指页面加载时,并不是一次性加载所有图片,而是仅加载用户视口内可见的图片,随着用户的滚动或其他操作,逐步加载更多图片。懒加载的核心思想是优化用户体验,减少不必要的资源消耗,特别是在长页面或有大量图片的情况下。
图片懒加载有诸多优势:
- 图片懒加载能减少加载时的线程数据,使得可视区内的图片快速加载。
- 图片懒加载是按需加载,当用户滚动页面,图片进入可视区域时才发起请求,大大减少了不必要的请求,优化了网络资源的使用,有效减轻了服务器的负担。
- 图片懒加载还能增强用户体验。用户在访问页面时,不需要等待所有图片加载完成,可以更快地看到可视区内的内容,减少了等待时间,提高了用户的满意度。
图片懒加载的实现原理
图片懒加载的基础原理是先将 img 标签的 src 属性设置为占位图, 通常是一张较小的图片或者空白图片,以减少初始页面加载时的资源请求。同时,为 img 标签设置一个自定义属性,比如 data-src,用来存储真实的图片地址。
当页面加载完成后,通过判断图片是否进入可视窗口来决定是否将自定义属性中的真实地址赋值给 src 属性,从而实现图片的延迟加载。这样做的好处是在页面加载初期,只加载必要的资源,提高页面的加载速度,减少服务器压力和网络资源的消耗。
实现图片懒加载的方式
原生 loading="lazy"
HTML5 中的 loading 属性可以直接在 <img> 标签上使用,通过设置 loading="lazy" 可以让浏览器推迟加载那些不在初始视口内的图片,从而减少页面的初始加载时间,以实现图片懒加载。现代浏览器(如 Chrome、Edge 和 Firefox)已经支持这一属性。使用loading="lazy"
<img src="image.jpg" alt="description" loading="lazy">
优点:
- 简单易用,不需要额外的 JavaScript。
- 由浏览器原生支持,性能优秀。
缺点:
- 浏览器支持有限,部分旧版浏览器可能不兼容。
- 自定义控制较少,比如加载时机的精确控制。
使用 JavaScript 实现懒加载
使用 JavaScript 实现懒加载主要是通过 JavaScript 判断 img 图片是否在当前视口的可是区域,如果在图片否在当前视口的可是区域则加载,否则就不加载。
IntersectionObserver API
IntersectionObserver 是一个现代浏览器 API,IntersectionObserver 接口(从属于 Intersection Observer API)提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。
用它来检测图片是否进入视口非常方便。这是实现懒加载的常用技术之一,兼容性较好。
HTML 代码
初始阶段 img 标签的 src 指向一个用来占位的小图片 placeholder.jpg,data-src 属性中才是原始需要展示的图片地址。
<img src="placeholder.jpg" data-src="oregion.jpg" alt="description" class="lazy-load" />
JavaScript 代码
接着我们通过 IntersectionObserver API 判断图片是否在当前视口:
// 懒加载函数
function lazyLoadImages() {
const images = document.querySelectorAll('.lazy-load');
const config = {
// null 表示相对于视口
root: null,
rootMargin: '0px',
// 元素 10% 可见时触发
threshold: 0.1
};
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src; // 将 data-src 替换为 src
img.classList.remove('lazy-load'); // 移除类名,防止重复观察
observer.unobserve(img); // 停止观察当前图片
}
});
}, config);
images.forEach(image => {
observer.observe(image); // 观察每个图片元素
});
}
// 页面加载后初始化懒加载
window.addEventListener('DOMContentLoaded', lazyLoadImages);
优点:
- 性能高效,利用浏览器 API 处理视口判断。
- 可以灵活配置加载时机。
缺点:
- 需要写一些 JavaScript 代码。
- 低版本浏览器(如 IE)不支持该 API,需要 polyfill。
滚动事件监听实现懒加载
使用滚动事件监听实现图片懒加载,是在 IntersectionObserver API 出现前实现图片懒加载的传统方式。主要是通过 getBoundingClientRect() 方法判断图片是否在可视区域。
getBoundingClientRect() 方法返回一个 DOMRect 对象,包含了元素相对于视口的位置信息。可以通过判断元素的顶部、底部、左侧和右侧与视口的关系来确定图片是否在可视区域内。例如,当图片的顶部距离小于视口高度,底部、右侧和左侧距离均大于 0 时,说明图片在可视区域内,可以将自定义属性中的真实地址赋值给src属性,实现图片的加载。
OK,了解使用 getBoundingClientRect() 实现图片懒加载的基本原理后,看看如何实现吧:
HTML 代码
一样的,初始阶段 img 标签的 src 指向一个用来占位的小图片 placeholder.jpg,data-src 属性中才是原始需要展示的图片地址。
<img src="placeholder.jpg" data-src="oregion.jpg" alt="description" class="lazy-load" />
JavaScript 代码
通过 getBoundingClientRect() 方法实现图片懒加载,需要频繁地监听滚动事件,实时计算图片的 DOMRact 对象的数值是否在视口之内。
function lazyLoad() {
const images = document.querySelectorAll('.lazy-load');
const inView = (img) => {
const rect = img.getBoundingClientRect();
return rect.top <= window.innerHeight && rect.bottom >= 0;
};
images.forEach((img) => {
if (inView(img)) {
img.src = img.dataset.src;
img.classList.remove('lazy-load');
}
});
}
window.addEventListener('scroll', lazyLoad);
window.addEventListener('resize', lazyLoad);
优点:
- 简单且兼容性好,适用于所有浏览器。
缺点:
- 对滚动事件频繁监听可能导致性能问题,特别是页面内容复杂时。
- 需要手动管理节流和去抖动。
注意: 文中介绍的实现方法还不够完善,没有添加图片失败的处理逻辑。懒加载图片加载失败时,需要处理好错误情况,可以设置备用图像或显示提示信息。
图片懒加载的注意事项
- SEO 考虑:图片懒加载可能影响搜索引擎对图片的抓取,建议在需要 SEO 优化的页面上谨慎使用,或确保图片在没有 JavaScript 的情况下也能加载。
- 占位图:为了防止图片懒加载时出现“白屏”现象,可以为每个图片预设一个占位图,或者使用透明的 SVG。
- 错误处理:懒加载图片加载失败时,需要处理好错误情况,可以设置备用图像或显示提示信息。
- 浏览器兼容性:虽然现代浏览器大部分支持懒加载相关技术,但对于老旧浏览器(如 IE),可能需要用 polyfill 或降级处理。
总结
图片懒加载是提升页面性能、减少资源消耗的有效方法,特别适用于图片较多的页面。原生 loading="lazy" 是最简单的实现方式,但支持有限。通过 getBoundingClientRect() 方法实现图片懒加载,兼容性好,但需要频繁地监听滚动事件,需要手动管理节流和去抖动。而使用 IntersectionObserver 实现懒加载应该是现代前端开发中最推荐的方式,性能优异且灵活。
文中的几种方法都各自的优缺点,大家在了解其实现原理后,根据需要自行选择使用。在未来,随着网页技术的不断发展和用户对网页性能要求的不断提高,JavaScript 图片懒加载技术也将不断演进和完善。应该会出现更加高效的算法和实现方式,进一步提高图片加载的速度和性能。作为前端开发人员就需要持续关注最新的技术更新。