概要
IntersectionObserver 接口提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)。
当一个 IntersectionObserver 对象被创建时,其被配置为监听根中一段给定比例的可见区域。可以在同一个观察者对象中配置监听多个目标元素。
当然IntersectionObserver不可能完全替代监听滚动条,只是相比于监听滚动条,IntersectionObserver更加方便快捷,并且目前大多数主流浏览器已经兼容
兼容性
IntersectionObserver 目前除了 IE 和 OperaMini,已经被主流的浏览器支持。
更多详情
const ob = new IntersectionObserver((e) => {
console.log(‘交叉触发回调’,e)
}, {
root:null,
rootMargin:'10px',
threshold: 0
})
ob.observe(目标dom)
回调函数参数说明
每次触发回调,会获得监听到的目标信息(回调接收的参数entries)
属性 | 说明 |
---|---|
boundingClientRect | 返回包含目标元素的边界信息,返回结果与element.getBoundingClientRect() 相同 |
intersectionRatio | 返回目标元素出现在可视区的比例,即交叉范围 |
intersectionRect | 用来描述root和目标元素的相交区域 |
isIntersecting | 返回一个布尔值,下列两种操作均会触发callback:1. 如果目标元素出现在root可视区,返回true。2. 如果从root可视区消失,返回false |
rootBounds | 用来描述交叉区域观察者(intersection observer)中的根. |
target | 目标元素:与根出现相交区域改变的元素 (Element) |
time | 返回一个记录从 IntersectionObserver 的时间原点到交叉被触发的时间的时间戳 |
配置项说明
-
root:观察目标与谁交叉,可为其父元素或父元素的父元素,null表示观察目标与视口交叉
-
rootMargin:观察的范围的偏移量,可以有效的缩小或扩大根的判定范围从而满足计算需要,偏移量可用像素(px)或百分比(%)来表达,默认值为
“0px 0px 0px 0px”。
- threshold:触发回调的阈值的列表,按升序排列,列表中的每个阈值都是监听对象的交叉区域与边界区域的比率。如果构造器未传入值,则默认值为0
使用功能场景
图片懒加载、video不可见时停止播放、监听当前页面课件区域,侧边导航高亮显示等
以监听当前页面课件区域,侧边导航高亮显示为例
//获取目标dom
const artical = document.querySelectorAll('.artical')
//被点击项的索引
let activeItemIndex = 0;
//获取全部导航项
let allListItem = dom.list.children
//创建观察者
function articalObserve() {
const ob = new IntersectionObserver((e) => {
//当目标离开时不触发
if (!e[0].isIntersecting) {
return
}
//获取与root交叉的元素中自定义的index
activeItemIndex = e[0].target.dataset.index
//高亮
this.moveTo(activeItemIndex)
}, {
root: document.querySelector('#head'),
//被观察元素与视口交叉
threshold: 0
})
dom.artical.forEach(item => {
//对目标进行观察
ob.observe(item)
})
}
//创建侧边导航
function getAsideList() {
const list = [
{ title: '概要' },
{ title: '一、相关定义' },
{ title: '二、我们如何收集和使用您的个人信息' },
{ title: '三、信息的存储' },
{ title: '四、信息安全' },
{ title: '五、我们分享的信息' },
{ title: '六、您的权利' },
{ title: '七、变更' },
{ title: '八、未成年人保护' },
{ title: '九、其他' },
{ title: '十、联系我们' },
]
for (let i = 0; i < list.length; i++) {
const div = document.createElement('div')
div.classList.add('list-item')
//自定义属性每部分的index
div.setAttribute('index', i)
//记录每个部分距离浏览器顶部高度,20为第一个部分距离页面顶部的偏移量
div.setAttribute('top', dom.artical[i].offsetTop - 20)
div.onclick = () => this.jumpTo(i, dom.artical[i].offsetTop - 20)
div.innerText = list[i].title
//将导航项加入到准备好的盒子
父元素的dom.appendChild(div)
}
}
//高亮显示
function moveTo(i) {
//移除之前元素的高亮
let activeA = document.querySelector('.active')
if (activeA) activeA.classList.remove('active')
//为当前项添加高亮
allListItem[i].classList.add('active')
}
//点击导航滑动到指定部分
function jumpTo(i, t) {
moveTo(i)
//滚动到指定位置
可滚动区域的dom.scrollTo({ top: t, behavior: 'smooth' })
}
运行效果
黄色区域为监听的根root,当每一部分与根(黄色区域)交叉时,触发回调,使导航高亮