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

356 阅读3分钟

这是我参与11月更文挑战的第14天,活动详情查看:2021最后一次更文挑战

前端面试时性能优化是一个考察的大方面,其中一种经典的方案就是懒加载,懒加载又包括图片懒加载、路由懒加载、数据懒加载等,今天我们来手把手实践一下实现图片懒加载的两种方式。

背景

<!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>
</head>
<body>
    <div style="height:800px;background-color: bisque;"></div>
    <div style="height:800px;background-color: blueviolet;"></div>
    <div style="height:800px;background-color: azure;"></div>
    <!--后面实践的时候需要把src改成data-src-->
    <img style='display:block' src='1.jpg'/>
    <img style='display:block' src='2.jpg'/>
    <img style='display:block' src='3.jpg'/>
</body>
</html>

我们以上面这个页面作为实践图片懒加载的背景,在一些div之后有三张图片,我们打开这个页面的时候开启调试面板,到network选项,会发现三张图片已完成加载。

image.png

原理

在开始实践之前,我们先来说说懒加载的原理。

试想一下前面作为实践背景的页面,如果图片不止三张,而是很多很多,那么在点开页面的时候就要对所有图片进行加载,那么页面加载速度就会很慢很慢,显然这不是我们想要的。

那懒加载是如何进行优化的呢?通过打开上面的页面我们可以发现一开始在视口内还没见到图片,要往下滚动才会看到,那没必要一进来就加载图片,或许用户都不用滚动到下方有图片的位置就已经离开这个页面了。懒加载就是当图片进入视口内的时候才开始加载资源。具体实践可以有两种方式,您请往下看:

实践

  1. 监听scroll事件 我们可以使用getBoundingClientRect().top来获取元素距离视窗上方的距离,然后用这个距离和视窗的高度(window.innerHeight)进行比较,如果大于则说明元素还未进入视窗,反之则将加载进入视窗的图片资源。代码如下:(注意吼,我们需要把上面image的src属性改为自定义的data-src属性噢)
 <script>
        const images=document.querySelectorAll('img');
        window.addEventListener('scroll',(e)=>{
            images.forEach(image=>{
                const imageTop=image.getBoundingClientRect().top;
                if(imageTop<window.innerHeight){
                     const data_src=image.getAttribute('data-src');
                     image.setAttribute('src',data_src);
                }
                console.log('触发')
            })
        })
    </script>

我们再次打开页面,可以发现没有一进来就加载图片资源了。

image.png 我们继续往下滑动页面,可以发现当图片进入视口的时候,图片资源就开始加载,然鹅会不断的加载,就像下面这样:

image.png 所以使用这种方法的话应该还得加个节流。锁定本频道,如无意外,后面会更一篇防抖节流滴~

  1. IntersectionObserver 交叉观察 目标元素会和可视窗口产生交叉区域,我们可以通过new一个IntersectionObserver的实例来对该区域进行观察,它有一个observe方法和unobserve方法,顾名思义就是观察和取消观察的方法。该构造函数第一个参数是一个回调函数,这个回调函数分别会在目标元素进入视口和离开视口的时候进行触发。
<script>
        const images=document.querySelectorAll('img');
        //callback函数的参数是一个数组,包含所有被观察元素的信息
        const callback=entries=>{
            entries.forEach(entry=>{
                if(entry.isIntersecting){//isIntersecting为true的话表示进入视口
                    const image=entry.target;//获取被观察元素
                    const data_src=image.getAttribute('data-src');
                    image.setAttribute('src',data_src); //开始加载图片资源之后就取消观察
                    observer.unobserve(image);
                }
            })
        }
        //创建IntersectionObserver实例
        const observer=new IntersectionObserver(callback);
        //对每个img元素进行观察
        images.forEach(image=>{
            observer.observe(image);
        })
    </script>

我们可以发现这样的话页面的图片资源就只会加载一次。

image.png 对图片懒加载的两种实践方式就讲到这里啦,11月份的更文也到这里告一段落,这是第一次写这么多技术文章,感觉收获不少。希望自己能把写技术文章坚持下去,下次见,朋友们!😊😊