朋友们,美好的一天!总览
Intersection Observer API(IOA)允许应用程序异步观察元素(目标)与其父元素(根)或视口(视口)的交集。换句话说,每次目标元素与根或视口相交时,此API都会提供对特定函数的调用。使用示例:- 延迟或延迟加载图像
- 无休止的页面滚动
- 接收有关广告可见度的信息,以计算印象费用
- 在用户的视野中启动过程或动画
要开始使用IOA,您需要使用构造函数来创建带有两个参数的观察者对象-回调函数和设置:
let options = {
root: document.querySelector('.scroll-list'),
rootMargin: '5px',
threshold: 0.5
}
let callback = function(entries, observer){
...
}
let observer = new IntersectionObserver(callback, options)
设定:- root-充当目标视口的元素(目标元素的祖先,视口为null)
- rootMargin-根周围的边距(CSS中的边距,默认情况下所有边距均为0)
- 阈值-一个数字或数字数组,指示目标和根的交点的可接受百分比
接下来,创建目标元素,观察者将对其进行观察:let target = document.querySelector('.list-item')
observer.observe(target)
回调调用返回一个对象,该对象包含目标元素发生的更改的记录:let callback = (entries, observer) => {
entries.forEach(entry => {
})
}
该网络充满了有关理论的信息,但是有关使用IOA的实践的材料很多。我决定填补这一空白。例子
延迟(延迟)图像加载
任务:在用户滚动页面时上传(显示)图像。编码:
window.onload = () => {
const options = {
root: null,
rootMargin: '0px',
threshold: 0.5
}
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const lazyImg = entry.target
console.log(lazyImg)
lazyImg.style.background = 'deepskyblue'
observer.unobserve(lazyImg)
}
})
}, options)
const arr = document.querySelectorAll('img')
arr.forEach(i => {
observer.observe(i)
})
}
结果:
视口外的容器的背景为白色。
当您跨过查看区域一半时,背景变为天蓝色。→ Codepen→ Github图像替换
任务:当用户滚动页面时,将占位符图像更改为原始图像。编码:window.onload = () => {
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
console.log(entry)
entry.target.src = entry.target.dataset.src
observer.unobserve(entry.target)
}
})
}, { threshold: 0.5 })
document.querySelectorAll('img').forEach(img => observer.observe(img))
}
结果:
第一张图像已上传,因为它在查看区域中。第二个是占位符。
当您进一步滚动时,占位符将替换为原始图像。→ Codepen→ Github更改容器背景
任务:当用户在那里滚动页面并返回时,更改容器的背景。编码:window.addEventListener('load', event => {
let box = document.querySelector('div')
let prevRatio = 0.0
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
let curRatio = entry.intersectionRatio
curRatio > prevRatio ? entry.target.style.background = `rgba(40,40,190,${curRatio})` : entry.target.style.background = `rgba(190,40,40,${curRatio})`
prevRatio = curRatio
})
}, {
threshold: buildThresholdList()
})
observer.observe(box)
function buildThresholdList() {
let thresholds = []
let steps = 20
for (let i = 1.0; i <= steps; i++) {
let ratio = i / steps
thresholds.push(ratio)
}
return thresholds
}
})
结果:
容器的背景从
浅蓝色...
变为蓝色... 变为浅红色。→ Codepen→ Github处理视频
任务:暂停正在运行的视频,然后根据落入查看区域的视频重新开始播放。编码:window.onload = () => {
let video = document.querySelector('video')
let observer = new IntersectionObserver(() => {
if (!video.paused) {
video.pause()
} else if(video.currentTime != 0) {
video.play()
}
}, { threshold: 0.4 })
observer.observe(video)
}
结果:
视频在观看区域中时,将播放。
一旦视频超出观看区域40%以上,其播放就会暂停。如果您查看的观看区域>视频的40%,将继续播放。→ Codepen→ Github页面浏览进度
任务:在用户滚动页面时显示查看页面的进度。编码:
let p = document.querySelector('p')
let n = 0
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if(entry.isIntersecting){
p.textContent = `${n++} div viewed`
observer.unobserve(entry.target)
}
})
}, {threshold: 0.9})
document.querySelectorAll('div').forEach(div => observer.observe(div))
结果:该
页面刚刚加载,因此我们尚未查看任何容器。
到达页面末尾时,该段落显示有关查看4格的信息。→ Codepen→ Github无限滚动
任务:实现无尽的清单。编码:let ul = document.querySelector('ul')
let n = 1
function createLi(){
li = document.createElement('li')
li.innerHTML = `${++n} item`
ul.append(li)
}
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
createLi()
}
observer.unobserve(entry.target)
observer.observe(document.querySelector('li:last-child'))
})
}, {
threshold: 1
})
observer.observe(document.querySelector('li'))
结果:
我们有12个列表项。最后一项在视口之外。
当您尝试到达最后一个元素时,将创建一个对用户隐藏的新(最后)元素。等等到无穷大。→ Codepen→ Github调整父母大小时调整孩子大小
任务:建立一个元素的大小对另一个元素的依赖性。编码:
let info = document.querySelector('.info')
let parent = document.querySelector('.parent')
let child = document.querySelector('.child')
child.style.width = parent.offsetWidth - 50 + 'px'
info.textContent = `child width: ${child.offsetWidth}px`
let options = {
root: parent,
threshold: 1
}
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
if ((entry.target.parentElement.offsetWidth - entry.target.offsetWidth) < 50) {
entry.target.style.width = entry.target.offsetWidth - 50 + 'px'
}
})
}, options)
observer.observe(child)
window.addEventListener('resize', () => {
info.textContent = `child width: ${child.offsetWidth}px`
if ((parent.offsetWidth - child.offsetWidth) > 51) {
child.style.width = child.offsetWidth + 50 + 'px'
}
})
结果:
初始状态。
当减小父元素的宽度时,子元素的宽度减小。同时,它们之间的距离几乎总是等于50px(“几乎”是由于采用了反向机制)。→ Codepen→ Github处理动画
任务:在可见时为对象设置动画。编码:
let observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
entry.isIntersecting ? entry.target.classList.replace('to-left', 'to-right') : entry.target.classList.replace('to-right', 'to-left')
})
}, {
threshold: .5
})
observer.observe(document.querySelector('img'))
结果:
我们看到了Bart头部的一部分。巴特按下到查看区域的左侧。
如果超过50%的Bart落入观看区域,他将移至中间。当超过50%的Bart离开查看区域时,它将返回其初始位置。→ Codepen→ Github谢谢您的关注。