前言
上一篇文章中我们探讨了前端路由的实现过程,从 hash 技术原理入手。这篇文章将聚焦于另一种优化技术——懒加载(Lazy Loading)。懒加载是现代 web 开发中一种重要的性能优化手段,它旨在延迟资源的加载,直至用户实际需要这些资源时再进行加载。对于 JavaScript 和前端开发而言,懒加载能够显著提升页面性能,特别是在需要处理大量内容或资源的场景中。本文将深入解析 JavaScript 中的懒加载技术及其具体应用场景。
正文
什么是懒加载?
懒加载是一种设计模式,指的是“按需加载”资源,而不是在页面加载时立即加载所有资源。这个过程的核心思想是延迟加载图片、视频、脚本或其他资源,直到它们进入视口(可视区域)或在用户需要时才开始加载。懒加载主要应用于图像、视频、API请求和大型JavaScript文件的加载。
为什么需要懒加载?
随着网站功能的增强和内容的增多,页面的加载时间越来越长。过多的资源请求会导致页面加载缓慢,影响用户体验。特别是在移动设备或网络不稳定的情况下,加载时间过长甚至可能导致用户流失。懒加载通过减少初始页面加载时所需的资源,能够大大提高页面的加载速度和性能。
懒加载的工作原理
懒加载的工作原理可以总结为以下几个步骤:
- 延迟加载:初始加载时,仅加载页面必需的资源。其他资源会在需要时再加载。
- 监听视口变化:通过监听用户的滚动或视口的变化,判断哪些资源进入了视口范围。
- 加载资源:当资源进入视口时,开始加载对应的资源。
- 替换占位符:加载完成后,用真实内容替换占位符,呈现给用户。
JavaScript中的懒加载实现
在JavaScript中,懒加载通常用于延迟加载图片、脚本或者其他静态资源。以下是图片的懒加载应用场景及其实现方式。
我们先看代码
代码示例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.img-item{
display: block;
height: 300px;
margin-top: 50px;
}
</style>
</head>
<body>
<img class = 'img-item' src='' data-oringinal="https://img2.baidu.com/it/u=4050062314,1116360005&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500" alt="">
<img class = 'img-item' src='' data-oringinal="https://img1.baidu.com/it/u=1052255644,1248205582&fm=253&fmt=auto&app=120&f=JPEG?w=1280&h=800" alt="">
<img class = 'img-item' src='' data-oringinal="https://pic1.zhimg.com/v2-98d4e142341bd4c7837c453b9e8571cb_r.jpg?source=1940ef5c" alt="">
<img class = 'img-item' src='' data-oringinal="https://img2.baidu.com/it/u=2527682571,2612045298&fm=253&fmt=auto&app=138&f=JPEG?w=889&h=500" alt="">
<img class = 'img-item' src='' data-oringinal="https://img0.baidu.com/it/u=3879160884,2524664469&fm=253&fmt=auto&app=120&f=JPEG?w=1422&h=800" alt="">
<img class = 'img-item' src='' data-oringinal="https://gimg2.baidu.com/image_search/data-oringinal=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2F60b50dcd-9ced-4e88-b6bb-9cd0c2b96d42%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1706187135&t=33c453c3dd6ff90c2e46f7f29c6df525" alt="">
<img class = 'img-item' src='' data-oringinal="https://gimg2.baidu.com/image_search/data-oringinal=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Ff726ac98-b6da-4003-a098-b9290b3738ef%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1706187135&t=5c51a20ed5926d36561f224ea6fcd514" alt="">
<img class = 'img-item' src='' data-oringinal="https://gimg2.baidu.com/image_search/data-oringinal=http%3A%2F%2Fsafe-img.xhscdn.com%2Fbw1%2Fa6a1a37b-b7e2-4a97-ade9-291a9e9e7e88%3FimageView2%2F2%2Fw%2F1080%2Fformat%2Fjpg&refer=http%3A%2F%2Fsafe-img.xhscdn.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1706187135&t=4c78e78b513850535f9879104cdba123" alt="">
<img class = 'img-item' src='' data-oringinal="https://img1.baidu.com/it/u=1496036918,1216480802&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500" alt="">
<img class = 'img-item' src='' data-oringinal="https://gimg2.baidu.com/image_search/data-oringinal=http%3A%2F%2Fc-ssl.duitang.com%2Fuploads%2Fblog%2F202107%2F23%2F20210723113501_ac0b1.thumb.1000_0.jpg&refer=http%3A%2F%2Fc-ssl.duitang.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1706187389&t=21afa270b2fabd1bb8064399de3d1a94" alt="">
<script>
// 判断图片有没有进入可视区域,有的话就将其data-original的值赋给src
let viewHeight = window.innerHeight
function lazyLoad() {
let imgs = document.querySelectorAll('img[data-oringinal]')
console.log(imgs);
imgs.forEach(el => {
let rect = el.getBoundingClientRect() // 获取容器的几何信息
if (rect.top < viewHeight) {
console.log(1111);
let image = new Image()
image.src = el.dataset.oringinal
image.onload = function() {
el.src = image.src
}
el.removeAttribute('data-oringinal')
}
})
}
lazyLoad()
document.addEventListener('scroll',lazyLoad)
</script>
</body>
</html>
代码讲解
JavaScript部分
定义视口高度
let viewHeight = window.innerHeight;
这里通过window.innerHeight获取浏览器窗口的可视区域高度(即视口高度)。这个值将用来判断图片是否进入视口。
lazyLoad函数
function lazyLoad() {
let imgs = document.querySelectorAll('img[data-oringinal]');
console.log(imgs);
imgs.forEach(el => {
let rect = el.getBoundingClientRect(); // 获取元素相对于视口的位置
if (rect.top < viewHeight) { // 如果图片的上边界已经进入视口
console.log(1111);
let image = new Image(); // 创建一个新的Image对象
image.src = el.dataset.oringinal; // 设置图片的真实URL
image.onload = function() { // 图片加载完成后
el.src = image.src; // 将图片的src属性设置为真实图片的URL
};
el.removeAttribute('data-oringinal'); // 删除data-oringinal属性,防止重复加载
}
});
}
这是懒加载的核心逻辑:
-
获取所有懒加载图片:通过
document.querySelectorAll('img[data-oringinal]')选中所有含有data-oringinal属性的图片元素。 -
检查图片是否进入视口:使用
el.getBoundingClientRect()获取每个图片元素相对于视口的位置。这个方法返回一个DOMRect对象,包含图片的top、left、right、bottom等信息。rect.top表示图片的上边界距离视口顶部的距离。- 如果
rect.top < viewHeight,说明图片已经进入了视口,或者至少部分进入了视口。
-
加载图片:如果图片进入视口:
- 创建一个新的
Image对象,并将其src属性设置为data-oringinal中存储的真实图片URL。 - 在图片加载完成后,执行
image.onload函数,将图片的src属性更新为真实图片的URL,从而触发浏览器加载图片并显示。
- 创建一个新的
-
移除
data-oringinal属性:为了避免重复加载,在成功加载后,将data-oringinal属性删除。
初次调用 lazyLoad() 和监听滚动事件
lazyLoad(); // 初次加载时检查哪些图片进入视口并进行加载
document.addEventListener('scroll', lazyLoad); // 每次滚动时再次检查
- 初次加载检查:在页面加载时,调用
lazyLoad()函数,检查当前已经进入视口的图片并加载它们。即使用户没有滚动页面,也会立即加载那些已经在视口中的图片。 - 滚动事件监听:使用
document.addEventListener('scroll', lazyLoad)监听滚动事件,当用户滚动页面时,会再次调用lazyLoad()函数,检查哪些图片进入了视口并加载。
懒加载的优化和注意事项
虽然懒加载能显著提升性能,但在实际应用中也有一些优化点和注意事项:
- 预加载(Preloading) :为了避免因懒加载导致的首次用户交互延迟,可以提前预加载一些关键资源。例如,滚动到页面底部时,可以提前加载一些接下来的图片或模块。
- SEO(搜索引擎优化) :如果懒加载资源是对搜索引擎索引至关重要的内容,需要确保搜索引擎能够抓取到这些资源。可以使用SSR(服务端渲染)或静态生成技术,确保懒加载的内容能在爬虫抓取时提前加载。
- 兼容性:虽然
IntersectionObserverAPI得到了大多数现代浏览器的支持,但在一些旧浏览器中(如Internet Explorer)可能不兼容。在这种情况下,可以使用scroll事件手动检查元素是否进入视口,或者引入polyfill来增强兼容性。 - 性能监控:懒加载虽然能够提升性能,但不当的实现可能会引起一些性能问题。例如,监听滚动事件时,如果不进行防抖处理,可能会导致频繁的DOM操作,影响性能。因此需要根据实际需求选择合适的技术和优化方式。
结语
无论你是前端新手还是经验丰富的开发者,掌握懒加载这一优化技术都将极大提升你的开发效率!通过合理使用懒加载,你可以有效提升页面加载速度,改善用户体验,按需加载资源,减少不必要的网络请求。希望这篇文章能够帮助你更全面地理解和应用 JavaScript 中的懒加载技术。别忘了关注我,带上你的伙伴一起来探索更多前端技巧和最佳实践!🚀
祝你在代码的世界中畅行无阻,创造出更高效的 Web 应用!👨💻👩💻