优化:图片懒加载

143 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情

首先了解为什么要图片懒加载

首先这是从客户角度进行的优化,为什么呢?

当我们的某一个页面有大量图片时,如果用户一进来就全部加载的话,则浏览器同时发送请求所有的网络资源,会给页面带来很大的负担,出现很长一段时间的空白,导致用户体验非常不好。 所以我们需要进行图片懒加载,减轻服务器的压力,优先加载可视区域的内容,那么其他部分等进入了页面可视区域再加载,从而提高性能和用户体验感!

解决方案

思路

  1. 先给所有的图片地址用自定义属性保存

  2. 当图片进入页面的可视区域之后,再将图片地址替换为真实的图片地址

拓展

什么是自定义属性

语法: data-xx

我们可以使用data-前缀设置我们需要的自定义属性进行一些数据的存放

<div id="images" data-src='xxx' ></div>

获取属性:

let img = document.getElementById('images')
let DataImg = img.dataset.src

如何判断图片是否进入可视区域

方法

利用浏览器提供的 IntersectionObserver,监听图片元素是否进入可视区域,进入后才真正去设置图片元素的 src 属性进行图片加载。

格式

var dom = dom元素
// 实例化一个观察者
// 它的参数1是一个回调:当被观察的目标进入视口/离开视口就会调用
var observer = new IntersectionObserver((entries)=>{
  console.log(entries[0].isIntersecting)
  console.log(entries[0].intersectionRatio)
  if(entries[0].isIntersecting) {
    
  }
}, 其他配置)


observer.disconnect()   // 停止观察者
observer.unobserve(dom) // 观察者停止对dom的观察

可以看出 IntersectionObserver 的回调函数当元素可见比例超过指定阈值后,会调用一个回调函数,此回调函数接受两个参数:

entries打印出来如图:

image.png

isIntersecting返回的是一个布尔值,我们可以利用它判断图片是否进入了可视区域

intersectionRatio 返回的是0/1/小数,表示的是图片出现在可视区域的占比

rootMargin

一个在计算交叉值时添加至根的边界盒中的一组偏移量,类型为字符串(string) ,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和CSS 中的margin属性等同

observe 开启观察者观察dom

observer.observe(dom)

disconnect 停止观察者

observer.disconnect()  

unobserve 观察者停止对dom的观察

observer.unobserve(dom)

例子(完整代码)

<!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>
        <p style="padding: 30px;">1</p>
        <p style="padding: 30px;">2</p>
        <p style="padding: 30px;">3</p>
        <p style="padding: 30px;">4</p>
        <p style="padding: 30px;">5</p>
        <p style="padding: 30px;">6</p>
        <p style="padding: 30px;">7</p>
        <p style="padding: 30px;">8</p>
        <p style="padding: 30px;">9</p>
        <img height="200" data-src="https://gimg2.baidu.com/image_search1/src=http%3A%2F%2Ffzn.cc%2Fwp-content%2Fuploads%2F2020%2F04%2F640-8.jpg&refer=http%3A%2F%2Ffzn.cc&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=jpeg?sec=1641365183&t=b5d7bdae0fe3f2c4831b52e3985abdf1" />
        <p style="padding: 30px;">1</p>
        <p style="padding: 30px;">2</p>
        <p style="padding: 30px;">3</p>
        <p style="padding: 30px;">4</p>
        <p style="padding: 30px;">5</p>
        <p style="padding: 30px;">6</p>
        <p style="padding: 30px;">7</p>
        <p style="padding: 30px;">8</p>
        <p style="padding: 30px;">9</p>
    </div>

    <script>
        var img = document.querySelector("img")
        var observer = new IntersectionObserver((arr)=>{
            console.log(arr,'arr');
            console.log(arr[0].isIntersecting)
            console.log(arr[0].intersectionRatio)
            if(arr[0].isIntersecting) {
                img.src = img.getAttribute('data-src')
                img.onerror = function(){
                    img.src="https://w.wallhaven.cc/full/wq/wallhaven-wqve97.png"
                }
            }
        }, {rootMargin: "100px"})

        observer.observe(img)
    </script>
</body>
</html>