js - IntersectionObserver的一些应用
场景:
* 图片懒加载 - 图片进入视口后再加载资源
* 无限滚动列表 - 滚动在列表最下方,再请求新数据
* 检测某个元素是否进入用户的画面
方案1:getBoundingRect()和onScroll
2016年之前使用getBoundingRect()和onScroll组合实时来获取元素相对左上角的距离来判断元素是否进入视口区域
缺点:触发频率高,无用计算太多,性能不好。如果和其他需要占用主线程的程序并行,比如动画,可能会有问题
方案1实现:
// 1.getBoundingRect获取元素是否进入视口
// (1) 监听的元素:1、需要有高度 2、overflow:auto or scroll;
function fromGetBoundingRect(element) {
const CSS = element.getBoundingClientRect();
wrap.addEventListener("scroll", (e) => {
const innerH = window.innerHeight;
const innerW = window.innerWidth;
const { top, height } = element.getBoundingClientRect();
if (top > 0 && top < innerH) inView = true;
if (Math.abs(top) <= height) inView = true;
if (CSS.height + top <= 0) inView = false;
console.log(inView ? "进入" : "离开");
});
}
fromGetBoundingRect(d2);
方案2:IntersectionOberve()
IntersectionObserver其实是监听元素与另一个元素(必须是目标元素的父级)交叉面积的占比监听问题
let observer = new IntersectionObserver(callback, options);
let options = {
root: document.querySelector('#scrollArea'),
rootMargin: '0px',
threshold: 1.0
}
callback
:回调函数
options
:调用回调函数的环境配置
root
=> 包裹目标的元素,计算目标在其中的占比,省略为窗口视窗
rootMargin
=> root的margin,可以控制threshold
threshold
=> 占比阀值,目标元素和root交叉的比例达到这个值触发回调函数,默认0可以是[ 0, 0.25, 0.5, 0.75, 1],即占比每变化25%触发一次回调函数
方案2实现:
let options = {
root: null,
rootMargin: '0px',
threshold: 0.0
}
const observer = new IntersectionObserver((entrys) => {
for (const v of entrys) {
console.log(v);
}
}, options);
observer.observe(d2); // 观察的目标元素d2
打印:(我是弟中弟是我的公众号哈)
intersectionRation
=> 就是目标元素和root之间的交叉区域的占比\
isIntersecting
=> 目标元素和root的可见性发生变化,这个变化的值就是你设置的阀值(isIntersecting)
ahooks的useInViewport
方法就是用IntersectionObserver
来实现的:
IntersectionObserver.disconnect
: 用来终止对所有目标元素可见性变化的观察,防止监听太多,页面关掉又忘记卸载,会导致内存泄漏
浏览器兼容性:
完整代码:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
html,
body {
height: 100%;
padding: 0;
margin: 0;
}
.wrap {
height: 100%;
overflow-y: scroll;
}
.d1,
.d3 {
height: 1000px;
width: 100%;
background-color: aquamarine;
}
.d2 {
height: 200px;
width: 100%;
background-color: burlywood;
}
</style>
</head>
<body>
<div class="wrap">
<div class="d1"></div>
<div class="d2"></div>
<div class="d3"></div>
</div>
</body>
<script>
const wrap = document.getElementsByClassName("wrap")[0];
const d1 = document.getElementsByClassName("d1")[0];
const d2 = document.getElementsByClassName("d2")[0];
let inView = false;
// 1.getBoundingRect获取元素是否进入视口
// (1) 监听的元素:1、需要有高度 2、overflow:auto or scroll;
// function fromGetBoundingRect(element) {
// const CSS = element.getBoundingClientRect();
// wrap.addEventListener("scroll", (e) => {
// const innerH = window.innerHeight;
// const innerW = window.innerWidth;
// const { top, height } = element.getBoundingClientRect();
// if (top > 0 && top < innerH) inView = true;
// if (Math.abs(top) <= height) inView = true;
// if (CSS.height + top <= 0) inView = false;
// console.log(inView ? "进入" : "离开");
// });
// }
// fromGetBoundingRect(d2);
// 2.IntersectionObserver监听
// IntersectionObserver其实是一个监听元素在可视区域内出现的占比问题
let options = {
root: null,
rootMargin: '0px',
threshold: 0.0
}
const observer = new IntersectionObserver((entrys) => {
for (const v of entrys) {
console.log(v);
}
}, options);
observer.observe(d2);
</script>
</html>
参考(MDN): developer.mozilla.org/zh-CN/docs/…
转载自:https://juejin.cn/post/7038407933742284831