前言
在需要使用大量图片时,如果我们打开页面时就加载所有的图片,那势必会导致页面的卡顿以及白屏,给用户不好的体验,导致用户流失。
但是我们仔细想一下,用户真的需要我们显示所有图片一起展示吗?其实并不是,用户看到的只是浏览器可视区域的内容。所以从这个情况我们可以做一些优化,只显示用户可视区域内的图片,当用户触发滚动的瞬间再去请求显示给用户, 所以图片懒加载的有势在必行。
图片懒加载的优点
-
减小资源的加载,页面启动只加载首屏的图片,这样能明显减少服务器的压力和流量,提高页面的加载速度,减少浏览器的负担
-
防止并发加载的资源过多而阻塞js加载,影响整个网站的启动
-
能提升用户的体验,不妨设想下,用户打开页面的时候,如果页面上所有的图片都需要加载,由于图片数目较大,等待时间很长这就严重影响用户体验
实现原理
图片的加载是由src的值引起的,当对src赋值时,浏览器会请求图片资源,基于这个,可以利用html5的属性data-xxx来保存图片的路径,当我们需要加载图片的时候才将data-xxx的值赋予src,就能实现突破的按需加载,也就是懒加载了
懒加载的基本思路
当dom元素进入可视区域时,才去加载它。
如何判断一个dom元素是否进入了可见区域?
- 传统: 获取dom的位置,手动判断。(距离页面顶部的距离 比较 滚动条卷起的高度,还要考虑元素自己的高度 )
- 现在:直接判断元素进入可视区域的比例
实现思路
利用浏览器提供的 IntersectionObserver,监听图片元素是否进入可视区域,进入后才真正去设置图片元素的 src 属性进行图片加载
IntersectionObserver 使用方法
IntersectionObserver() 构造器创建并返回一个IntersectionObserver对象。 如果指定rootMargin则会检查其是否符合语法规定,检查阈值以确保全部在0.0到1.0之间,并且阈值列表会按升序排列。如果阈值列表为空,则默认为一个[0.0]的数组
语法 :
var observer = new IntersectionObserver(callback[, options]);
参数:
-
callback -
当元素可见比例超过指定阈值后,会调用一个回调函数,此回调函数接受两个参数:
-
entries一个
IntersectionObserverEntry对象的数组,每个被触发的阈值,都或多或少与指定阈值有偏差。 -
observer被调用的
IntersectionObserver实例。
-
-
options可选 -
一个可以用来配置observer实例的对象。如果
options未指定,observer实例默认使用文档视口作为root,并且没有margin,阈值为0%(意味着即使一像素的改变都会触发回调函数)。你可以指定以下配置:-
root监听元素的祖先元素
Element对象,其边界盒将被视作视口。目标在根的可见区域的的任何不可见部分都会被视为不可见。 -
rootMargin一个在计算交叉值时添加至根的边界盒(bounding_box (en-US))中的一组偏移量,类型为字符串(string) ,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和CSS 中的
margin属性等同; 可以参考 The root element and root margin in Intersection Observer API来深入了解margin的工作原理及其语法。默认值是"0px 0px 0px 0px"。 -
threshold
规定了一个监听目标与边界盒交叉区域的比例值,可以是一个具体的数值或是一组0.0到1.0之间的数组。若指定值为0.0,则意味着监听元素即使与根有1像素交叉,此元素也会被视为可见. 若指定值为1.0,则意味着整个元素都在可见范围内时才算可见。可以参考Thresholds in Intersection Observer API 来深入了解阈值是如何使用的。阈值的默认值为0.0。
var dom = dom元素 // 实例化一个观察者 // 它的参数1是一个回调:当被观察的目标进入视口/离开视口就会调用 var observer = new IntersectionObserver((entries)=>{ console.log(entries[0].isIntersecting) console.log(entries[0].intersectionRatio) if(entries[0].isIntersecting) { } }, 其他配置) // 观察者观察dom observer.observe(dom) observer.disconnect() // 停止观察者 observer.unobserve(dom) // 观察者停止对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>
<style>
div {
width: 200px;
height: 200px;
background-color: skyblue;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<img data-src="https://tse2-mm.cn.bing.net/th/id/OIP-C.P3NSGTdAYdyqy5zJpb5QXQHaEo?pid=ImgDet&rs=1" alt="">
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<div></div>
<script>
const img = document.querySelector('img')
const observer = new IntersectionObserver(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://tse4-mm.cn.bing.net/th/id/OIP-C.Yu52PeiUicZhrQgZFa-qTgAAAA?pid=ImgDet&rs=1'
}
}
}, { rootMargin: "100px" })
observer.observe(img)
</script>
</body>
</html>
效果:
滚动前: 不发请求获取图片资源
达到一定的视口距离: 获取图片资源
当图片加载失败 : 这里给的是错误的图片路径
<img data-src="https://tse25-mm.cn.bing.net/th/id/OIP-C.P3NSGTdAYdyqy5zJpb5QXQHaEo?pid=ImgDet&rs=1" alt="">
效果 : 加载图片资源失败 ,替换为失败默认图片
总结 :
-
为提高网站加载性能,图片懒加载是必要的。
-
图片懒加载是实现原理是判断当前图片是否到了可视区域进行加载,可通过监听 scroll 事件和 IntersectionObserver 实现相应的功能