懒加载IntersectionObserver 深入理解
IntersectionObserver
callback
var observer = new IntersectionObserver(callback,options);
callback 监听元素的可见性
options 配置参数
callback
一般会触发两次,一次是目标进入视口(可见),另一次是完全离开(不可见)
let observer = new IntersectionObserver(changes => {
changes.forEach(change => {
// 完全可见时为1,完全不可见时小于等于0
console.log(change.intersectionRatio);
// 被观察的目标元素,是一个 DOM 节点对象
// 当前可视区域正在变化的元素
console.log(change.target);
})
})
如果没设置Option 就只触发两次
每一个属性的含义
time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒
target:被观察的目标元素,是一个 DOM 节点对象
rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null
boundingClientRect:目标元素的矩形区域的信息
intersectionRect:目标元素与视口(或根元素)的交叉区域的信息
intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0
time: 3893.92 🔽rootBounds: ClientRect bottom: 920 height: 1024 left: 0 right: 1024 top: 0 width: 920
option
threshold 属性
threshold 属性决定了什么时候触发回调函数
new IntersectionObserver( entries => {/* ... */}, { threshold: [0, 0.25, 0.5, 0.75, 1] } );
比如,[0, 0.25, 0.5, 0.75, 1]就表示当目标元素 0%、25%、50%、75%、100% 可见时,会触发回调函数。
root属性 rootMargin属性
root属性指定目标的容器节点(根元素)
属性 | 说明 |
---|---|
root | 监听元素的祖先元素 Element 对象 |
rootMargin | 一个在计算交叉值时添加至根的边界盒(bounding_box)中的一组偏移量,类型为字符串,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和 CSS 中的 margin 属性等同,默认值是"0px 0px 0px 0px" top、right、bottom 和 left单位: “ px ”,”% |
threshold | 规定了一个监听目标与边界盒交叉区域的比例值,可以是一个具体的数值或是一组 0.0 到 1.0 之间的数组。若指定值为 0.0,则意味着监听元素即使与根有 1 像素交叉,此元素也会被视为可见. |
{
root: Element,
rootMargin: string,
threshold: number | number[]
}
默认
{
root: null,
rootMargin: "0px 0px 0px 0px",
threshold: [0]
}
使用
方法 | 说明 |
---|---|
disconnect() | 使 IntersectionObserver 对象停止监听工作。 |
observe() | 使 IntersectionObserver 开始监听一个目标元素。 |
unobserve() | 使 IntersectionObserver 停止监听特定目标元素。 |
IntersectionObserver
使用的是异步的方式,可以不用担心性能问题
- 开始观察某个猎物:
observer.observe(el)
- 取消观察某个猎物:
observer.unobserve(el)
- 自爆,关掉这个观察器:
observer.disconnect()
可见性demo
const target = document.getElementById('target')
const observer = new IntersectionObserver((entries) => {
const [entry] = entries
if (entry.isIntersecting) {
console.log('元素曝光了')
}
})
observer.observe(target)
懒加载
为了惰性加载图片,当然不能把 img 的 src 直接设置成图片地址,不然浏览器直接就显示了。而一般是放在
data-src
属性中,或增加lazy-load
类。<img data-src="https://example.com/me.png" width="100px" height="50px" /> 找到所有需要惰性加载的图片 var images = document.querySelectorAll('img[data-src]'); var observer = new IntersectionObserver(onIntersection); images.forEach(img => { observer.observe(img); });
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
const [entry] = entries
if (entry.isIntersecting) {
entry.target.src='xxxx';
// 取消监控
observer.unobserve(entry.target)
}
})
observer.observe(target)
当猎物进入到镜头后,isIntersecting会是true,不在镜头内就是false。
解释
- intersectionRatio 相交比例。刚开始相交是0%,相交一半是50%,完全进入则是100%
- isIntersecting 是否正在相交。
intersectionRatio != 0
即正在相交。(后来增加的属性) - target 被观察的元素。
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if(entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
});
root 的理解
<div style="height:400px;overflow-y:scroll">
<div style="height:200vh;background-color: khaki;"></div>
<div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
<div style="height:200vh;background-color: khaki;"></div>
</div>
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
}, {
root: document.querySelector('#aaa'),
});
observer.observe(target)
rootMargin
<div style="height:200vh;background-color: #f00d0d;"></div>
<div style="height:400px;overflow-y:scroll;" class="aaa">
<div id="ccc" style="height:500px;background-color: #b1ff6d;"></div>
<div style="height:200vh;background-color: khaki;"></div>
</div>
const target = document.getElementById('ccc')
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log("元素相交");
} else {
console.log("元素不相交");
}
});
}, {
root: document.querySelector('#aaa'),
rootMargin:'50%' //根 400px 50% 是200px
/* 距离下面200px的时候相交*/
/* 距离下面200px的时候不相交*/
});
observer.observe(target)
决定自己的高度的是你的态度,而不是你的才能
记得我们是终身初学者和学习者
总有一天我也能成为大佬