前端性能优化之图片懒加载

背景

如果网页中有很多的图片,一次性拿到所有的图片会导致流量消耗很大,图片加载也会比较缓慢。造成用户体验感差,使用图片懒加载可以极大的提升用户体验,懒加载是一种网页性能优化的方式,进入页面的时候,之请求可视化区域的图片资源。

为什么要使用图片懒加载?总结出以下两点:
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 交叉观察 目标元素和可视窗口会产生交叉区域,观察交叉区域,发生了什么事情,然后执行什么样的程序。

IntersectionObserver(callback,参数二)

是浏览器原生提供的构造函数,接收两个参数,第一个参数是一个callback回调函数,可见变化的回调函数,第二个参数是option配置参数(可选参数),在这里只说一下第一个参数,在图片懒加载里面的使用。

目标元素和可视化窗口会产生交叉区域,观察交叉区域发生的变化,执行对应的程序 实例可以进行开始和结束观察DOM节点  callback 目标元素看到了触发一次,看不到又触发一次。
// 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

 

posted @ 2021-08-02 14:39  〆浮生如梦〆  阅读(576)  评论(0)    收藏  举报