intersectionObserver
监听目标元素与其祖先元素或视口交叉状态
实现懒加载
observeVisible = () => {
/**
* @param {function} callback - 目标元素可见性发生变化时调用,一般会触发两次,目标刚进入视口,目标完全离开视口
@param {array} entries - IntersectionObserverEntry对象数组, e.g. 同时有两个被观察对象的可见性发生变化,entries数组就会有两个成员
e.g. [{
time: 3893.92, // 可见性发生变化的时间戳
intersectionRatio: 0.54, // 目标元素可见比例,完全可见:1,完全不可见:0
target: element, // 被观察元素,DOM节点
isIntersecting: true, // 是否处于相交状态
rootBounds: ClientRect { // 根元素矩形区域信息,getBoundingClientRect()的返回值,没有根元素返回null
bottom: 920,
height: 1024,
left: 0,
right: 1024,
top: 0,
width: 920
},
boundingClientRect: ClientRect { // 目标元素的矩形区域信息
// ...
},
intersectionRect: ClientRect { // 目标元素与视口(或根元素)的交叉区域信息
// ...
}
}]
* @param {object} option - 配置,可选
{
threshold: {number || Array},判断元素可见的阀值,[0, 1)
默认为0 || [0],即交叉比例(intersectionRatio),只要交叉比例大于0,e.g. 0.0000001:元素视为可见,0:元素视为不可见
0.8, intersectionRatio > 0.8:元素视为可见,intersectionRatio < 0.8:元素视为不可见
[.5, .8],intersectionRatio > 0.5 || intersectionRatio > 0.8:元素视为可见,触发两次可见的回调,intersectionRatio < 0.5:元素视为不可见,触发一次隐藏的回调
root: 指定视口元素
rootMargin: 用于扩展或缩小视口的大小,从而影响intersection交叉区域的大小
}
*
* @desc 实例方法
- observer.observe(document.getElementById('example')); // 开始观察
参数是一个DOM节点,观察多个节点需多次调用 e.g. observer.observe(elementA); observer.observe(elementB);
- observer.unobserve(element); // 停止观察
- observer.disconnect(); // 关闭观察器
* */
const observer = new IntersectionObserver((entries) => {
entries.forEach((item) => {
// 元素可见
if (item.intersectionRatio > 0) {
const element = item.target;
element.innerText = 'Done';
observer.unobserve(element);
}
})
});
const lazyloadItems = document.querySelectorAll('.lazy-loaded');
Array.from(lazyloadItems).forEach((item) => {
observer.observe(item);
})
};
<div style={{ width: 300, height: 300, overflow: 'auto' }}>
<div id='1' className='lazy-loaded' style={{ width: 300, height: 150, boxSizing: 'border-box', backgroundColor: 'gray' }}></div>
<div id='2' className='lazy-loaded' style={{ width: 300, height: 150, boxSizing: 'border-box', backgroundColor: 'gray' }}></div>
<div id='3' className='lazy-loaded' style={{ width: 300, height: 150, boxSizing: 'border-box', backgroundColor: 'gray' }}></div>
<div id='4' className='lazy-loaded' style={{ width: 300, height: 150, boxSizing: 'border-box', backgroundColor: 'gray' }}></div>
<div id='5' className='lazy-loaded' style={{ width: 300, height: 150, boxSizing: 'border-box', backgroundColor: 'gray' }}></div>
</div>
实现无限下拉加载更多
observeVisible = () => {
const endItem = document.querySelector('#sentinels');
const scrollView = document.querySelector('#scrollView');
const observer = new IntersectionObserver((entries) => {
entries.forEach((item) => {
// 底部元素可见
if (item.intersectionRatio > 0) {
const newItem = document.createElement('div');
newItem.style.cssText = 'width:300px; height:150px; background-color:gray';
scrollView.insertBefore(newItem, endItem);
}
})
});
observer.observe(endItem);
};
<div id='scrollView' style={{ width: 300, height: 300, overflow: 'auto' }}>
<div style={{ width: 300, height: 150, backgroundColor: 'gray' }}></div>
<div style={{ width: 300, height: 150, backgroundColor: 'gray' }}></div>
<div style={{ width: 300, height: 150, backgroundColor: 'gray' }}></div>
<div style={{ width: 300, height: 150, backgroundColor: 'gray' }}></div>
<div style={{ width: 300, height: 150, backgroundColor: 'gray' }}></div>
<div id='sentinels'></div>
</div>
参考文章:https://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html