IntersectionObserver用法
- 1.什么是IntersectionObserver?
- 2.使用
- 2.1 创建观察对象
- 2.2 观察指定DOM对象
- 2.3 参数详解
- (1)callback参数
- (2)options 配置参数
- 3.应用
- 3.1 Dom进入页面的加载动画
- 3.2 图片的懒加载
1.什么是IntersectionObserver?
IntersectionObserver接口,提供了一种异步观察目标元素与其祖先元素或顶级文档视窗交叉状态的方法。可能很多人听不懂啥意思,那也没关系,看下面的示例能理解就可以了。
2.使用
2.1 创建观察对象
let observer = new IntersectionObserver(callback, options)
2.2 观察指定DOM对象
observer.observe(DOM元素)
observer观察者对象在观察元素是否进入视口、祖先元素的时候,不管元素是否进入,都会触发观察者对象的回调函数!
let box = document.querySelector('.box')
let observer = new IntersectionObserver(function(entries){
console.log(entries)
})
observer.observe(box)
可以发现,程序一开始会默认执行一次输出,因为box盒子默认就在视口当中,所以会触发一次;
2.3 参数详解
如下是IntersectionObserver
的使用格式:
let observer = new IntersectionObserver(function(entries,observer){
//回回调函数接受两个参数,第二个可以不写,因为用处不大
}, options)
(1)callback参数
回调函数接受两个参数,分别是:
- 所有被监听的dom对象集合,一般用 entries 表示;
- 以及观察者对象,一般用observer表示,可写可不写。
在entries集合中的每一个元素都是被监听的对象,被监听的对象上有一些属性。可以打印一下看看:
由上可知IntersectionObserverEntry对象格式如下:
{
time: 3893.92,
rootBounds: ClientRect {
bottom: 920,
height: 1024,
left: 0,
right: 1024,
top: 0,
width: 920
},
boundingClientRect: ClientRect {
// ...
},
intersectionRect: ClientRect {
// ...
},
intersectionRatio: 0.54,
isIntersecting:false,
isVisible:false,
target: element
}
其中比较常用的属性是:
time
:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒target
:被观察的目标元素,是一个 DOM 节点对象rootBounds
:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回nullboundingClientRect
:目标元素的矩形区域的信息isIntersecting
:true表示当前元素进入视口,false表示当前元素离开视口intersectionRect
:目标元素与视口(或根元素)的交叉区域的信息intersectionRatio
:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
注意:操作entries集合中的Dom对象,记得加索引!
let box = document.querySelector('.box');
let observer = new IntersectionObserver(function(entries){
console.log( entries[0].isIntersecting );
})
observer.observe(box)
(2)options 配置参数
options是一个对象,有三个参数:
第一个参数: root: 祖先级对象 | null
:
root
属性的值可以是一个祖先级对象,这时,主要的是针对局部的滚动效果。当root属性不写,或者值为null时,表示的是监听DOM元素与当前视口的交叉关系!
第二个参数:rootMargin: 视口的外延值
相当于扩大视口的范围:
rootMargin
属性是规定视口的外延值,相当于扩大了视口的范围,用于提早触发观察者回调函数。
如下图:
第三个参数:threshold:0-1
表示当被观察者进入视口百分之多少时触发观察者:
threshold
默认值是0,表示刚进入时就触发观察者的回调函数,完全离开时,再触发观察的回调;当threshold
的值是1,表示当被监听元素完全进入视图在触发观察者的回调函数,当元素刚离开时,再触发观察的回调。
如果把threshold
设为0-1中间的某值:
3.应用
3.1 Dom进入页面的加载动画
如下图:
代码如下:
<style>
.show{
transform: translateY(0) scale(1);
opacity: 1;
}
.hide{
transform: translateY(100%) scale(0);
opacity: 0;
}
//css样式可自行决定,这里虽然没写,但别忘了添加transtion过渡属性,让动画更加平滑
<style>
<body>
<ul class="list">
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
<script>
let lis = document.querySelectorAll(".list li");
let observer = new IntersectionObserver(function(entries){
// 2 这里会接收到所有被观察的 dom 对象
for(let i = 0; i < entries.length; i++ ){
//遍历所有被观察对象,判断其是否出现在视口
if( entries[i].isIntersecting ){
//为true则表示出现在视口,然后为其添加出现样式
entries[i].target.classList.remove('hide');
entries[i].target.classList.add('show')
}
else{
//为flase则表示消失在视口,然后为其添加消失样式
if( entries[i].boundingClientRect.top > 0 ){
//这里是判断li是否是往下消失
entries[i].target.classList.remove('show');
entries[i].target.classList.add('hide')
}
}
}
});
for(let i = 0; i < lis.length; i++ ){
observer.observe(lis[i])
// 1 给所有li添加监听观察
}
</script>
核心逻辑是:通过css给指定元素添加过渡属性,然后使用观察对象监听每个元素,给默认在视口中的元素做最终值的处理,给不在视口中的元素做初始值的处理。那么当元素进入视口的时候,初始值 -> 最终值 就会应用过渡动画!
3.2 图片的懒加载
如下图:
代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
box-sizing: border-box;
}
ul{
list-style: none;
}
.box{
width: 80%;
margin: 0 auto;
display: flex;
flex-wrap: wrap;
}
.item{
width: calc( 33.33% - 20px );
margin: 10px;
min-height: 200px;
}
.item img{
width: 100%;
}
</style>
</head>
<body>
<div class="box">
<!-- <div class="item">
<img src="./img/Empty.svg" alt="">
</div> -->
</div>
</body>
<script>
//先做一个数组,用来装图片的网络地址
let imgList = [
{
default:'./img/Empty.svg', //这是默认生效的图片,你可以改成自己的
url:'https://images.pexels.com/photos/23719800/pexels-photo-23719800.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/20569931/pexels-photo-20569931.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/23105903/pexels-photo-23105903.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/22816073/pexels-photo-22816073.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/18197764/pexels-photo-18197764.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/24031902/pexels-photo-24031902.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/23914518/pexels-photo-23914518.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/16118941/pexels-photo-16118941.jpeg?auto=compress&cs=tinysrgb&w=800&lazy=load'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/22937531/pexels-photo-22937531.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/21915597/pexels-photo-21915597.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/16703290/pexels-photo-16703290.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/13298586/pexels-photo-13298586.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/18109714/pexels-photo-18109714.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/22670156/pexels-photo-22670156.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/21852583/pexels-photo-21852583.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/21367366/pexels-photo-21367366.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/17102067/pexels-photo-17102067.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/24038436/pexels-photo-24038436.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/19473669/pexels-photo-19473669.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/20470948/pexels-photo-20470948.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/22469105/pexels-photo-22469105.jpeg?auto=compress&cs=tinysrgb&w=800&lazy=load'
}
,
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/13743557/pexels-photo-13743557.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=2'
},
{
default:'./img/Empty.svg',
url:'https://images.pexels.com/photos/23230661/pexels-photo-23230661.jpeg?auto=compress&cs=tinysrgb&w=800&lazy=load'
},
]
let box = document.querySelector('.box');
//渲染页面结构的工具函数,用来遍历list,然后渲染成dom结构到页面
function initImg(list){
for( let i = 0; i < list.length; i++ ){
let div = document.createElement('div');
div.className = 'item';
let img = document.createElement('img');
img.src = list[i].default;
img.dataset.url= list[i].url;
div.appendChild(img);
box.appendChild(div);
}
}
initImg(imgList);//先调用一次工具函数
window.onload = function(){
//这里要等页面加载完毕,也就是默认图片加载完毕后,再执行之后的逻辑
let items = document.querySelectorAll('.item');
Observer(items);//调用观察者工具函数,给其传要观察的Dom对象
}
//观察者工具函数
function Observer(list){
let observer = new IntersectionObserver(function(entries){
for(let n = 0; n < entries.length; n++ ){
if( entries[n].isIntersecting && entries[n].target.children[0].src.includes( "img/Empty.svg" ) ){
entries[n].target.children[0].src = entries[n].target.children[0].dataset.url;
}
}
})
for(let i = 0; i < list.length; i++ ){
observer.observe(list[i])
}
}
</script>
</html>
核心逻辑是:通过src加载一张本地的默认图片,然后通过data-url引入真实的地址。当图片进入视口以后,使用data-url的图片地址,替换src的图片地址,实现图片只有进入视口时才加载的效果。