过去,要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。比如,下面这些情况都需要用到相交检测:
Intersection Observer API 允许你配置一个回调函数,当以下情况发生时会被调用
每当目标 (target) 元素与设备视窗或者其他指定元素发生交集的时候执行。设备视窗或者其他元素我们称它为根元素或根 (root)。

Observer 第一次监听目标元素的时候。
每当被监视的元素进入或者退出另外一个元素时 (或者 viewport ),或者两个元素的相交部分大小发生变化时,该回调方法会被触发执行。
Intersection Observer API 无法提供重叠的像素个数或者具体哪个像素重叠,他的更常见的使用方式是——当两个元素相交比例在 N% 左右时,触发回调,以执行某些逻辑。
目标 (target) 元素与根 (root) 元素之间的交叉度是交叉比 (intersection ratio)。这是目标 (target) 元素相对于根 (root) 的交集百分比的表示,它的取值在 0.0 和 1.0 之间。
创建一个 IntersectionObserver 对象,并传入相应参数和回调用函数,该回调函数将会在目标 (target) 元素和根 (root) 元素的交集大小超过阈值 (threshold) 规定的大小时候被执行。
let options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
let observer = new IntersectionObserver(callback, options);

callback
callback是添加监听后,当监听目标发生滚动变化时触发的回调函数。接收一个参数entries,即IntersectionObserverEntry实例。描述了目标元素与root的交叉状态。具体参数如下:

方法
介绍了这么多配置项及参数,差点忘了最重要的,IntersectionObserver有哪些方法?
如果要监听某些元素,则必须要对该元素执行一下observe

<!DOCTYPE html>
<html>
<head>
<title>IntersectionObserver</title>
<style>
.body {
width: 100%;
height: 2000px;
}
img {
width: 150px;
}
</style>
</head>
<body>
<div class="body">
<img src="" alt="img" data-src="./img.jpg">
</div>
</body>
<script>
var imgs = [...document.querySelectorAll('img')]
const io = new IntersectionObserver(entries=>{
console.log(entries,'触发回调函数')
entries.forEach(item=>{
if(item.isIntersecting) {
item.target.src = item.target.dataset.src
io.unobserve(item.target)
}
})
})
imgs.forEach(item=>io.observe(item))
// observe是IntersectionObserver的方法,监听一个目标元素
</script>
</html>
图片懒加载

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>吸顶</title>
<style>
body {
margin: 0;
}
.display {
width: 100%;
height: 3000px;
background-color: #d0d0d0;
}
.back {
display: flex;
}
.btn {
background: #999997;
color: #757575;
text-align: center;
line-height: 40px;
width: 100px;
height: 40px;
margin-right: 14px;
border-radius: 20px;
cursor: pointer;
}
.cur {
width: 130px;
background-color: #fff;
}
</style>
</head>
<body>
<div class="display ">
<div class="hold">
<div class="back">
<div class="cur btn">露营</div>
<div class=" btn">飞盘</div>
<div class=" btn">吃饭</div>
<div class=" btn">划水</div>
</div>
</div>
<img src="./img.jpg" alt="" style="width: 100%;">
</div>
</body>
<script>
const cur = document.querySelector('.hold')
const back = document.querySelector('.back')
const io = new IntersectionObserver(entries => {
entries.forEach(item => {
if (!item.isIntersecting) {
back.style.cssText = 'position: fixed; top: 0; left: 0;'
} else {
back.style.cssText = ''
}
})
},{threshold: 1,})
io.observe(cur) // 监听对象
</script>
</html>
吸顶
单词sticky的中文意思是“粘性的”,position:sticky表现也符合这个粘性的表现。基本上,可以看出是position:relative和position:fixed的结合体——当元素在屏幕内,表现为relative,就要滚出显示器屏幕的时候,表现为fixed。
注意点:
sticky消失
案例实现
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>吸顶</title>
<style>
body {
margin: 0;
}
.display {
width: 100%;
height: 3000px;
background-color: #d0d0d0;
}
.back {
display: flex;
position: -webkit-sticky;
position: sticky;
top: 10px; // 相对最近的父元素高度而言
margin: 50px 0 0;
}
.btn {
background: #999997;
color: #757575;
text-align: center;
line-height: 40px;
width: 100px;
height: 40px;
margin-right: 14px;
border-radius: 20px;
cursor: pointer;
}
.cur {
width: 130px;
background-color: #fff;
}
</style>
</head>
<body>
<div class="display ">
<div class="back">
<div class="cur btn">露营</div>
<div class=" btn">飞盘</div>
<div class=" btn">吃饭</div>
<div class=" btn">划水</div>
</div>
<img src="./img.jpg" alt="" style="width: 100%;">
</div>
</body>
</html>
sticky
function loadMore() {
const observer = new IntersectionObserver(
(entries) => {
const loadingEntry = entries[0]
if (loadingEntry.isIntersecting) {
// 请求数据并插入列表
}
},
{
rootMargin: '0px 0px 600px 0px', // 提前加载高度
},
)
observer.observe(document.querySelector('.mod_loading')) // 观察尾部元素
}
