当你进入我的眼帘,我们的命运就有了交集~
看到 Observer,应该就知道今天要介绍的又是「观察者」系列的 API 了,而且这次的观察者可能比前面的 MutationObserver 和 ResizeObserver 还要实用。只要有了它,Scroll Animation 就只是一块小蛋糕了。
IntersectionObserver 帮我们观察的是元素的「相交(intersect)」变动,也就是元素与指定可视窗口的「相交与否」发生变动时触发。
简单来说就是页面元素因卷动而进入到可视范围中,或是离开了可视范围时,IntersectionObserver 就会执行指定任务,所以我们可以利用它来侦测「某个元素是不是进入视窗中」了,而且还可以调整许多细微的侦测设定,相当强大。
和其他「观察者」一样,IntersectionObserver
为一个建构函示,需要使用 new
关键字来创建实体,并且需要传入 Callback Function 作为参数,该 Callback 会获得一个存放 IntersectionObserverEntry 的阵列以及「观察者(observer)」自身实体,
this
。const observer = new IntersectionObserver((entries, owner) => {
console.log(owner); // IntersectionObserver 实体
entries.forEach((entry) => {
console.log(entry); // IntersectionObserverEntry 物件
});
});
另外,IntersectionObserver 除了 Callback 之外还有一个可选的 options
参数可以设定:
const callback = function (entries) {
console.log(entries);
};
const observer = new IntersectionObserver(callback, {
root: null,
rootMargin: "0px 0px 0px 0px",
threshold: 0.0,
});
这个 options
参数须为物件,并接受上面这三个属性:
null
,表示以 Viewport 作为判断依据,也可以设定成其他元素。margin
,可以给定一个值,也可以四边各自设定,正值为外扩,负值为内缩。0
: 当相交范围的比例「开始大於 0%」或「开始小於 0%」 的瞬间会触发。1
: 当相交范围的比例「开始大於 100%」或「开始小於 100%」 的瞬间会触发。[0, 0.5, 1]
: 规则如上,但目标元素就会有三个触发时机。
老样子,观察者们都需要我们使用 observe
method 来指定观察对象:
const observer = new IntersectionObserver((entries) => {
console.log(entries);
});
const div = document.querySelector("div");
observer.observe(div);
若要注销某元素的观察,IntersectionObserver 一样有 unobserve
method 可以使用:
const observer = new IntersectionObserver((entries) => {
console.log(entries);
});
const div = document.querySelector("div");
observer.observe(div);
observer.unobserve(div);
当然也可以一次性的注销所有元素的观察,同样要记得,IntersectionObserver 实体并不会消失,只是没有观测中的元素而已,你依然可以再次使用 observe
来注册一个新的观察:
const observer = new IntersectionObserver((entries) => {
console.log(entries);
});
const box1 = document.querySelector(".box1");
const box2 = document.querySelector(".box2");
observer.observe(box1);
observer.disconnect();
observer.observe(box2);
IntersectionObserver 和之前介绍的 MutationObserver 和 ResizeObserver 不同,它是**「非同步」**触发的,毕竟「相交与否」这件事情是一个瞬间,不会有不断叠加的状态,所以也就不需要考虑连续触发导致的效能问题,也就是说尽管你非常快速的来回卷动,它也不会将事件合并。
而 IntersectionObserverEntry 需要用阵列存放,是因为会有多个观测中的元素同时进入/离开可视范围的可能,这时候每一笔的 IntersectionObserverEntry 便代表一个元素的变动,而其中有许多属性可以提供我们使用,下面就一一向各位介绍:
isIntersecting
是当中非常实用的属性,用来表示目前元素是否与可是范围(root)相交,也就是目标元素是否进入到可视范围中。const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 目标元素进入 viewport 时执行
} else {
// 目标元素离开 viewport 时执行
}
});
});
相交面积 / 目标元素面积
。target
去执行昨天介绍的 getBoundingClientRect
所得到的结果。getBoundingClientRect
资讯,但计算的是可视窗口的尺寸、座标,要记得有 rootMargin
的影响。
IntersectionObserver 的使用情境很多,可以做「卷动特效」或是「无限卷动」,下面我们就来试试写个无间卷动的功能看看,先看效果:
<ul class="list">
<li class="item">
<div class="avatar"></div>
<div>
<h3>Name</h3>
<h5>
Lorem ipsum dolor sit, amet consectetur adipisicing elit. Rem tenetur odit.rem ipsum dolor sit, amet consectetur
adipisicing elit. Rem tenetur odit
</h5>
</div>
</li>
</ul>
const ul = document.querySelector("ul");
// 这个 function 会一次新增20笔项目到 ul 中
// 用来模拟获取资料後渲染画面
const getMoreItem = () => {
const fragment = document.createDocumentFragment();
for (let i = 0; i <= 20; i++) {
const item = document.querySelector("li:first-child");
const newItem = item.cloneNode(true);
fragment.appendChild(newItem);
}
ul.appendChild(fragment);
};
const observer = new IntersectionObserver(
function (entries, observer) {
// 每当目标元素进入画面後就新增20笔,并且重置观察的元素
if (entries[0].isIntersecting) {
getMoreItem();
observer.unobserve(entries[0].target);
observer.observe(document.querySelector("li:nth-last-child(2)"));
}
},
{ root: ul } // 观察窗口为 ul 的元素范围
);
getMoreItem();
observer.observe(document.querySelector("li:nth-last-child(2)"));
无限卷动的功能是非常常见的一个功能,平常在滑 FB 或 IG 时,贴文能不段的出现就是使用无线卷动,而使用 IntersectionObserver 就可以轻松做到。
我们实践的概念也非常简单,就是在目标元素进入窗口时去向後端获取资料并渲染在画面上,然後不断的重新观察倒数第二个 li
,所以可以看到 Callback 中有执行 unobserve
来注销原本的元素,然後又再次使用 observe
来注册新元素。
IntersectionObserver 是不是非常方便呢?昨天我们还在用 getBoundingClientRect
来计算元素是否进入画面,今天已经连计算都不用计算,完全交由「观察者」来帮忙侦测,我们只要坐等通知就好了,大家快把它学起来,当个懒惰的工程师吧!
<<: Day22 - 针对 Metasploitable 3 进行渗透测试(3) - Msfvenom 与 multi/handler
>>: Day 22 Password Attacks - 密码攻击(hashcat)
情境 在做大数据分析时,由於需要从几千万甚至几亿笔资料中做运算,应用程序就整个不能动,若中间机器有要...
#odoo #开源系统 #数位赋能 #E化自主 总结 终於来到了30天IT铁人赛的最终回,这30天内...
基本运算子 最最基本的运算子-赋值运算子 「=」 是最基本的运算子,它的作用是将 「=」 右方的数值...
我今天来讲下如何看手册操作暂存器好了,就以简单的GPIO口hi low就好,我手边刚有STM32F4...
阿修的说文解字 何谓 CORS? MDN 大大表示: CORS(Cross-Origin Resou...