IntersectionObserver
定义 IntersectionObserver提供了一种异步观察目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的方法。其祖先元素或视口被称为根(root)
1.IntersectionObserver() 构造器创建并返回一个IntersectionObserver对象
传入两个参数
1.回调函数
回调函数接收两个对象,
entries :一个IntersectionObserverEntry对象的数组,每个被触发的阈值,都或多或少与指定阈值有偏差。
observer : 被调用的IntersectionObserver实例。
2.配置对象
options :一个可以用来配置 observer 实例的对象。如果options未指定,observer 实例默认使用文档视口作为 root,并且没有
margin,阈值为 0%(意味着即使一像素的改变都会触发回调函数)。你可以指定以下配置:
root:监听元素的祖先元素Element对象,其边界盒将被视作视口。目标在根的可见区域的的任何不可见部分都会被视
为不可见。 传入的是dom对象,如果 为 null 则将试图窗口作为父元素
rootMargin:一个在计算交叉值时添加至根的边界盒 (bounding_box (en-US)) 中的一组偏移量,类型为字符串
(string) ,可以有效的缩小或扩大根的判定范围从而满足计算需要。语法大致和 CSS 中的margin 属性等同;
threshold :规定了一个监听目标与边界盒交叉区域的比例值,可以是一个具体的数值或是一组 0.0 到 1.0 之间的数组。
若指定值为 0.0,则意味着监听元素即使与根有 1 像素交叉,此元素也会被视为可见。若指定值为 1.0,则意味
着整个元素都在可见范围内时才算可见
3.返回值
一个可以使用规定阈值监听目标元素可见部分与root交叉状况的新的IntersectionObserver 实例。调用自身的observe() 方法开始
使用规定的阈值监听指定目标
<div class="observe">
<div class="demo">
<div>列表1</div>
<div>列表2</div>
<div>列表3</div>
<div>列表4</div>
<div>列表5</div>
<div>列表6</div>
<div ref="refDom">列表7</div>
<div>列表8</div>
<div>列表9</div>
<div>列表10</div>
<div ref="refDomBottom">列表11</div>
</div>
</div>
const options = {
// root: document.getElementsByClassName("observe")[0],
root: null,
rootMargin: "0px 0px -200px 0px",
threshold: 0.5
};
const changeMsg = (entries, observer) => { console.log("entries", entries);
console.log("observer", observer);
console.log("交叉触发了方法");
console.log("Observer.root", Observer.root); };
const Observer = new IntersectionObserver(changeMsg, options);
2.回调函数中 entries 和observer 参数详细
entries 参数:
boundingClientRect:返回包含目标元素的边界信息的DOMRectReadOnly. 边界的计算方式与 Element.getBoundingClientRect() 相同。
intersectionRatio:返回intersectionRect 与 boundingClientRect 的比例值。 即出发该事件的时候,元素与视图窗口相交的比例
intersectionRect:用来描述根和目标元素的相交区域。
isIntersecting:如果返回 true, 则 IntersectionObserverEntry 描述了变换到交叉时的状态; 如果返回 false, 那么可以由此判
断,变换是从交叉状态到非交叉状态。即 如果是true 则是非交叉状态到交叉状态,如果是false 则是交叉状态到非交叉状态
rootBounds:返回一个 DOMRectReadOnly 用来描述交叉区域观察者 (intersection observer) 中的根。
target:与根出现相交区域改变的元素 (Element).
time:返回一个记录从IntersectionObserver 的时间原点 (time origin) 到交叉被触发的时间的时间戳
observer 参数: 被调用的IntersectionObserver实例
3.observe() IntersectionObserver 对象监听的目标集合添加一个元素。一个监听者有一组阈值和一个根,但是可以监视多个目标元素,以查看这些目标元素可见区域的变化
使用:
const options = {
// root: document.getElementsByClassName("observe")[0],
root: null,
rootMargin: "0px 0px -200px 0px",
threshold: 0.5
};
const changeMsg = (entries, observer) => {
console.log("entries", entries);
console.log("observer", observer);
console.log("交叉触发了方法");
console.log("Observer.root", Observer.root); };
const Observer = new IntersectionObserver(changeMsg, options);
const refDom = ref();
const refDomBottom = ref();
//此处用来监听 refDom 和 refDomBottom 的元素与视图窗口的交叉
nextTick(() => { Observer.observe(refDom.value);
Observer.observe(refDomBottom.value); });
4.unobserve() IntersectionObserver的unobserve() 方法命令IntersectionObserver停止对一个元素的观察
参数: dom值
因为会在首次渲染的时候出发 所以可以添加条件判断 触发的时候是否符合自己的需求,在进行去掉观察
例如: 但元素出现在视图中的时候在进行取消掉观察
const refDom = ref();
const changeMsg = (entries, observer) => {
const windHeight = window.innerHeight;
// 满足条件 去掉对一个元素的观察
if(refDom.value.getBoundingClientRect().bottom <= windowHeight)
{ Observer.unobserve(refDom.value);
console.log("取消了观察refDom.value");
}
};
5. disconnect() 方法终止对所有目标元素可见性变化的观察。
无参数
const changeMsg = (entries, observer) => {
// 满足条件去掉所有元素的观察
if (refDom.value.getBoundingClientRect().bottom <= windowHeight) {
Observer.disconnect();
console.log("取消了所有的Observer的观察");
}
};
6. 实现图片的懒加载
1.创建IntersectionObserver对象
2.设置 options 配置
-
传入回调函数,在回调函数中设置图片的 地址,实现懒加载
<template> <div class="imageLazyDemo"> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <img ref="imageRef" :src="imgUrl" alt="" /> </div> </template> <script setup> import { ref, toRef, reactive, isReactive, toRaw, nextTick } from "vue"; const imgUrl = ref(); const imageRef = ref(); const options = { root: null, rootMargin: "0px 0px 200px 0px", threshold: 1 }; const windowHeight = window.innerHeight; const changeMsg = (entries, observer) => { console.log(entries[0].boundingClientRect.bottom); if (entries[0].boundingClientRect.bottom < windowHeight + 200) { console.log("触发"); // 设置图片的值 imgUrl.value = require("@/assets/logo.png"); } }; const Observer = new IntersectionObserver(changeMsg, options); nextTick(() => { Observer.observe(imageRef.value); }); </script> <style lang="scss" scoped> .imageLazyDemo { display: flex; flex-direction: column; align-items: center; div { width: 200px; height: 200px; background: red; margin-top: 20px; } } </style>
7.元素滚动 固定定位和取消定位按钮的位置
1.创建IntersectionObserver对象
2.设置 options 配置
-
传入回调函数, 在回调函数中判断 最后一个dom 的位置,如果在视图窗口中,则将清楚按钮的 固定定位,如果没有在视图窗口中 则取消掉按钮的固定定位
<template> <div class="imageLazyDemo"> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div>标题</div> <div ref="floatFlag">此处显示出来按钮浮动</div> <button ref="buttonRef">浮动的按钮</button> <div style="height: 200px"></div> <!-- <img ref="imageRef" :src="imgUrl" alt="" /> --> </div> </template> <script setup> import { ref, toRef, reactive, isReactive, toRaw, nextTick } from "vue"; const floatFlag = ref(); const buttonRef = ref(); const options = { root: null, rootMargin: "0px 0px 0px 0px", threshold: 1 }; const windowHeight = window.innerHeight; const changeMsg = (entries, observer) => { if (entries[0].boundingClientRect.bottom > windowHeight) { buttonRef.value.setAttribute("style", "position: fixed;top: 700px"); } else { buttonRef.value.setAttribute("style", ""); } }; const Observer = new IntersectionObserver(changeMsg, options); nextTick(() => { Observer.observe(floatFlag.value); }); </script> <style lang="scss" scoped> .imageLazyDemo { display: flex; flex-direction: column; align-items: center; div { width: 200px; height: 200px; background: red; margin-top: 20px; } } </style>