前端性能优化之图片懒加载
背景
如果网页中有很多的图片,一次性拿到所有的图片会导致流量消耗很大,图片加载也会比较缓慢。造成用户体验感差,使用图片懒加载可以极大的提升用户体验,懒加载是一种网页性能优化的方式,进入页面的时候,之请求可视化区域的图片资源。
为什么要使用图片懒加载?总结出以下两点:
1、浪费用户流量,有些用户并不想全部看完。一次性全部加载会耗费大量的流量;
2、全部加载的话会影响用户体验。
实现原理:
在html里面使用img标签,用自定义属性,将图片的路径放进去,使用data-*来表示,浏览器碰到这样的属性不会像默认属性那样去进行属性处理。
通过监听scroll事件,获取两个高度,分别是可视化区域的高度,可以使用window.innerHeight获取,图片元素距离可视化区域顶部高度的距离,可以用元素的getBoundingClientRect().top来获取。如果图片没有看到,也就是说图片距离视窗顶部的距离大于窗口显示区域的高度,如果图片可以看到了,就说明图片距离视窗顶部的距离小于窗口显示区域的高度。当图片元素出现在可视化区域的时候,获取data-src里面的值,赋值给img的src属性。
html内容
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> img { display: block; } </style> </head> <body> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <img data-src="https://scpic.chinaz.net/Files/pic/pic9/202012/apic29527_s.jpg" alt=""> <img data-src="https://scpic.chinaz.net/Files/pic/pic9/202012/apic29509_s.jpg" alt=""> <img data-src="https://scpic2.chinaz.net/Files/pic/pic9/202009/apic27858_s.jpg" alt=""> <img data-src="https://scpic2.chinaz.net/Files/pic/pic9/202001/zzpic22829_s.jpg" alt=""> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 DOM 事件细节。</p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <img data-src="https://scpic.chinaz.net/files/pic/pic9/202107/apic34240.jpg" alt=""> <img data-src="https://scpic.chinaz.net/files/pic/pic9/202107/apic34237.jpg" alt=""> <img data-src="https://scpic3.chinaz.net/Files/pic/pic9/202107/apic34235_s.jpg" alt=""> <img data-src="https://scpic3.chinaz.net/Files/pic/pic9/202107/apic34234_s.jpg" alt=""> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <img data-src="https://scpic3.chinaz.net/Files/pic/pic9/202107/bpic23807_s.jpg" alt=""> <img data-src="https://scpic2.chinaz.net/Files/pic/pic9/202107/apic34240_s.jpg" alt=""> <img data-src="https://sucai.gaoding.com/topic/11409" alt=""> <img data-src="https://sucai.gaoding.com/material/16616156" alt=""> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <img data-src="https://scpic1.chinaz.net/Files/pic/pic9/202105/apic32534_s.jpg" alt=""> <img data-src="https://scpic.chinaz.net/Files/pic/pic9/202103/hpic3645_s.jpg" alt=""> <img data-src="https://scpic.chinaz.net/Files/pic/pic9/202009/apic27943_s.jpg" alt=""> <img data-src="https://scpic1.chinaz.net/Files/pic/pic9/201804/zzpic11624_s.jpg" alt=""> </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <p>在事件处理程序中调用 event.preventDefault() 或 event.stopPropagation() 是非常常见的需求。尽管我们可以在方法中轻松实现这点,但更好的方式是:方法只有纯粹的数据逻辑,而不是去处理 </p> <img data-src="https://scpic3.chinaz.net/Files/pic/pic9/202106/apic33328_s.jpg" alt=""> <img data-src="https://scpic.chinaz.net/Files/pic/pic9/202004/zzpic24469_s.jpg" alt=""> <img data-src="https://scpic3.chinaz.net/Files/pic/pic9/201909/zzpic20188_s.jpg" alt=""> <script src="./index.js"></script> </body> </html>
第一种方法:直接监听scroll事件
// 首先获取图片元素 const images = document.querySelectorAll("img") // 1、直接监听scroll事件 window.addEventListener("scroll", (e) => { // 每次滚动验证图片是否出现在可视区域 images.forEach(image => { console.log(image) const imgTop = image.getBoundingClientRect().top // 获取每张图片距离可视化区域顶部距离 if (imgTop < window.innerHeight) { const data_src = image.getAttribute("data-src") image.setAttribute("src", data_src) } console.log("scroll触发") }); })
直接监听scroll事件,只要滚动浏览器就会触发事件,滚动区域会被多次执行,导致仁务堆积,资源消耗,计算量很大,容易造成性能问题。所以推荐使用IntersectionObserver 交叉观察 目标元素和可视窗口会产生交叉区域,观察交叉区域,发生了什么事情,然后执行什么样的程序。
是浏览器原生提供的构造函数,接收两个参数,第一个参数是一个callback回调函数,可见变化的回调函数,第二个参数是option配置参数(可选参数),在这里只说一下第一个参数,在图片懒加载里面的使用。
// const observer = new IntersectionObserver
// observer.observe(Dom节点)
// observer.unobserve(Dom节点) // 取消观察
// 2、使用IntersectionObbserver观察
const callback = entries => {
entries.forEach(items => {
if (items.isIntersecting) {
const image = items.target;
const data_src = image.getAttribute("data-src")
image.setAttribute("src", data_src)
observer.unobserve(image)
console.log("触发")
}
});
};
const observer = new IntersectionObserver(callback);
//每次循环的时候使用observer实例的observe方法来观察每一个img节点
images.forEach(item => {
observer.observe(item)
});
IntersectionObserver参考地址:https://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html

浙公网安备 33010602011771号