IntersectionObserver的使用

102 阅读4分钟

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) 到交叉被触发的时间的时间戳

0

observer 参数: 被调用的IntersectionObserver实例

0

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 配置

  1. 传入回调函数,在回调函数中设置图片的 地址,实现懒加载

    <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 配置

  1. 传入回调函数, 在回调函数中判断 最后一个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>