一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第9天,点击查看活动详情
首先了解为什么要图片懒加载
首先这是从客户角度进行的优化,为什么呢?
当我们的某一个页面有大量图片时,如果用户一进来就全部加载的话,则浏览器同时发送请求所有的网络资源,会给页面带来很大的负担,出现很长一段时间的空白,导致用户体验非常不好。 所以我们需要进行图片懒加载,减轻服务器的压力,优先加载可视区域的内容,那么其他部分等进入了页面可视区域再加载,从而提高性能和用户体验感!
解决方案
思路
-
先给所有的图片地址用自定义属性保存
-
当图片进入页面的可视区域之后,再将图片地址替换为真实的图片地址
拓展
什么是自定义属性
语法: data-xx
我们可以使用data-
前缀设置我们需要的自定义属性进行一些数据的存放
<div id="images" data-src='xxx' ></div>
获取属性:
let img = document.getElementById('images')
let DataImg = img.dataset.src
如何判断图片是否进入可视区域
- 传统: 获取dom的位置,手动判断。(距离页面顶部的距离 比较 滚动条卷起的高度,还要考虑元素自己的高度 )
- 现在:直接判断元素进入可视区域的比例
方法
利用浏览器提供的 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
是一个IntersectionObserverEntry
对象的数组,每个被触发的阈值,都或多或少与指定阈值有偏差。 -
observer
被调用的IntersectionObserver
实例。
entries打印出来如图:
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>