前言
我们在网页开发中,经常需要监听某个元素是否进入了可视区域内,从而进行相关操作,例如懒加载等;之前的做法大多都是通过监听 scroll 事件,通过获取目标元素的当前位置与视窗位置进行判断,通过这种方法需要监听 scroll 事件并且同时需要获取元素当前位置,会进行大量计算重绘等操作,可能会使页面卡顿,降低用户体验。
IntersectionObserver 接口,可以代替我们手动监听元素,可以自动“观察”元素是否可见。
一、完整测试代码
<!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="width:1500px;height:1000px;background-color: red"></div>
<img
src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.daimg.com%2Fuploads%2Fallimg%2F180314%2F1-1P314150U4.jpg&refer=http%3A%2F%2Fimg.daimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259323&t=16e41dd0fbee7f16745d8fe5c12fe1ef"
data-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2F4k%2Fs%2F02%2F2109242332225H9-0-lp.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259108&t=372ec13b2f081b4b7194762f5630ff5c"
>
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.daimg.com%2Fuploads%2Fallimg%2F180314%2F1-1P314150U4.jpg&refer=http%3A%2F%2Fimg.daimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259323&t=16e41dd0fbee7f16745d8fe5c12fe1ef" data-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fpic.jj20.com%2Fup%2Fallimg%2F1011%2F010QG05111%2F1F10Q05111-3.jpg&refer=http%3A%2F%2Fpic.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259323&t=5ff4b80dd0506b088c02527b05409573"
>
<img src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.daimg.com%2Fuploads%2Fallimg%2F180314%2F1-1P314150U4.jpg&refer=http%3A%2F%2Fimg.daimg.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259323&t=16e41dd0fbee7f16745d8fe5c12fe1ef" data-src="https://gimg2.baidu.com/image_search/src=http%3A%2F%2Fimg.jj20.com%2Fup%2Fallimg%2Ftp08%2F39042223172520.jpg&refer=http%3A%2F%2Fimg.jj20.com&app=2002&size=f9999,10000&q=a80&n=0&g=0n&fmt=auto?sec=1666259323&t=7824d87aea3191b3166357ecbef5f4ec"
>
<script>
const images = document.querySelectorAll('img');
// 1. onscroll事件监听
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('scroll')
})
})
// 2. IntersectionObserver
const callback = entries => {
entries.forEach(entry => {
console.log(entry,'entry')
if(entry.isIntersecting) {
const image = entry.target;
const data_src = image.getAttribute('data-src');
image.setAttribute('src',data_src);
observer.unobserve(image);
console.log('触发')
}
})
}
const observer = new IntersectionObserver(callback);
images.forEach(image => {
observer.observe(image)
})
</script>
</body>
</html>
二. IntersectionObserver
IntersectionObserver接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗 (viewport) 交叉状态的方法。祖先元素与视窗 (viewport) 被称为根 (root)。
当一个IntersectionObserver对象被创建时,其被配置为监听根中一段给定比例的可见区域。一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;然而,你可以在同一个观察者对象中配置监听多个目标元素。
1. 用法
该API的调用非常简单:
const io = new IntersectionObserver(callback, option);
上面代码中,IntersectionObserver 是浏览器原生提供的构造函数,接受两个参数:
(1)callback:可见性发现变化时的回调函数;
(2)option:配置对象(可选)
构造函数的返回值是一个观察器实例。实例一共有4个方法:
(1)observe:开始监听特定元素
(2)unobserve:停止监听特定元素
(3)disconnect:关闭监听工作
(4)takeRecords:返回所有观察目标的对象数组
1.1 observe
该方法需要接收一个target参数,值是Element类型,用来指定被监听的目标元素
// 获取元素
const target = document.getElementById(“dom”);
// 开始观察
io.observe(target);
1.2 unobserve
该方法需要接收一个target参数,值是Element类型,用来指定停止监听的目标元素
// 获取元素
const target = document.getElementById(“dom”);
// 停止观察
io.unobserve(target);
三. 兼容性
此api可能在部分设备及浏览器中不支持,这时我们可以降级使用 onscroll 事件,可以使用下面的函数来判断浏览器是否支持。
const canUseIntersectionObserver = () =>
'IntersectionObserver' in window &&
'IntersectionObserverEntry' in window &&
'intersectionRatio' in window.IntersectionObserverEntry.prototype;