亲宝软件园·资讯

展开

Intersection Observer交叉观察器示例解析

完锤子 人气:0

前言

作为一个前端搬砖仔,偶尔会遇到关于视窗的问题...

其中就经常会遇到一些数据上报问题,比如某某组件是否被用户看到了,如果看到就要上报数据,让产品同学方便进行数据分析。

分析这个场景可以发现,必须要用户看到了我才能上报,怎么判断用户是否看到了这个组件呢?

传统的方法是操作dom,通过这些数据或方法(offsetTop、scrollTop,getBoundingClientRect)来进行比较。

频繁的对DOM状态的计算,会造成不小的性能损耗,导致页面卡顿。

接下来介绍一种我最近比较常用的新方式:Intersection Observer(交叉观察器)

Intersection Observer 翻译过来即交叉观察器

主要是用于监听目标元素与指定的元素视窗是否发生交叉

一句话总结:Intersection Observer API 提供了一种异步检测目标元素与祖先元素或 viewport 相交情况变化的方法。 – MDN

使用

一、利用IntersectionObserver构造函数创建一个观察器实例

 <template>
  <div class="home"></div>
</template>
<script>
export default {
  name: "HomeView",
  mounted() {
    // 可见性发生变化后的回调
    function callback() {
      console.log("触发了");
    }
    // 交叉观察器配置项
    let options = {};
    // 生成交叉观察器
    const observer = new IntersectionObserver(callback);
  },
};
</script>

(callback是当元素可见比例超过指定阈值后会调用的一个回调函数,options是一个可以用来配置 observer 实例的对象。)

输出一下IntersectionObserver构造函数返回的实例

实例属性:

root:root 属性用来获取当前 intersectionObserver 实例的根元素,用于判断元素是否可见区域。

(注:这个既可以是 target 元素祖先元素也可以是指定 null 则使用浏览器视口 做为容器 (root)。)

rootMargin:一个类似于margin的字符串参数,就可以使用 root margin 来调整根矩形大小。

(注:由于使用Intersection Observer的过程中所有区域均被当做一个矩形看待,因此当我们需要调整元素边界的矩形时,用 root margin 来调整大小。)

threshold:阈值,可以传一个0 ~ 1的number,也可以传个0 ~ 1范围的number数组。

(注:如果传一个0 ~ 1的number,如0.5则说明,目标元素和root相交超过50%时,即二者重合超过目标元素的50%时,触发回调,如果是一个数组[0.1, 0.2, 0.5]则分别在10% 20% 50%处触发回调)

二、观察器实例监听元素相交

<template>
  <div class="home">
    <div id="target" class="target-item"></div>
  </div>
</template>
<script>
export default {
  name: "HomeView",
  mounted() {
    // 可见性发生变化后的回调
    function callback(data) {
      console.log("触发了");
      console.log(data);
    }
    // 交叉观察器配置项
    let options = {};
    // 生成交叉观察器
    const observer = new IntersectionObserver(callback);
    // 获取目标节点
    let target = document.getElementById("target");
    // 监听目标元素
    observer.observe(target);
  },
};
</script>
<style scoped>
.home {
  height: 300vh;
}
.home .target-item {
  margin-top: 120vh;
  width: 20px;
  height: 20px;
  background: #000;
}
</style>

可以看到

通过滚动,可以不停监听到观察器的回调。

三、观察器回调函数参数

看到在观察器的回调中是返回了一个对象的,修改原来的回调函数,对应看看到底返回了啥?

export default {
  name: "HomeView",
  mounted() {
    // 可见性发生变化后的回调
    function callback(data) {
      console.log("触发了");
      data.map((item) => {
        // 目标元素的getBoundingClientRect的返回值。
        console.log(item.boundingClientRect);
        // 目标元素和根元素交叉区域的getBoundingClientRect的返回值。
        console.log(item.intersectionRatio);
        // 目标元素的可见比例,相当于二者重合了多少。
        console.log(item.intersectionRect);
        // 目标元素与根元素是否相交
        console.log(item.isIntersecting);
        // 根元素的getBoundingClientRect的返回值
        console.log(item.rootBounds);
        // 目标元素,是个dom
        console.log(item.target);
        // 从首次创建观察者到触发指定阈值发生交叉的时间
        console.log(item.time);
      });
    }
    // 交叉观察器配置项
    let options = {
      threshold: 0.5,
    };
    // 生成交叉观察器
    const observer = new IntersectionObserver(callback, options);
    // 获取目标元素
    let target = document.getElementById("target");
    // 监听目标元素
    observer.observe(target);
  },
};

可以看到控制台输出了下述内容:

可以看到返回了很多东西

其中就有我们熟悉的元素的getBoundingClientRect属性。

回调参数属性:

boundingClientRect: 对象,返回了目标元素的getBoundingClientRect的返回值。

intersectionRatio:对象,返回了目标元素和根元素交叉区域的getBoundingClientRect的返回值。

intersectionRect: 数字,目标元素的可见比例,相当于二者重合了多少。

isIntersecting: 布尔值,目标元素与根元素相交是否相交

(如果相交,则返回 true ,若为true则说明至少到达了一个阈值,如果为false,说明目标元素在阈值范围内不可见)

rootBounds: 对象,返回了根元素的getBoundingClientRect的返回值。

target:对象,目标元素,是个dom

time: 数字,从首次创建观察者到触发指定阈值发生交叉的时间

因此通过观察器的回调参数可以做到精确监听目标的,通过这些参数可以更好的支持如下拉加载技术上报等场景,由于该属性是原生api因此比起频繁的操作dom会来的更丝滑。

四、观察器的实例方法

通过上文我们已经说明了,如何使用交叉观察器,并介绍了观察器的实例属性及回调参数

下面说一下观察器的实例方法!

    // 生成交叉观察器
    const observer = new IntersectionObserver(callback, options);
    // 获取目标元素
    let target = document.getElementById("target");
    // 监听目标元素
    observer.observe(target);

可以看到监听目标元素的时候用了 observe 方法,这就是观察器的实例方法之一—— 监听目标元素

观察器的实例方法一共有四个

disconnect:停止对所有的目标元素的观察

observe:监听目标元素(可监听多个)

takeRecords:返回一个IntersectionObserverEntry对象数组(观察器回调参数就是这个),里面存放的各个目标元素的相交信息

unobserve:停止对一个指定目标元素的观察

通过代码来演示下上述方法:

<template>
  <div class="home">
    <div id="target1" class="target1-item"></div>
    <div id="target2" @click="unobserve()" class="target2-item"></div>
    <div style="margintop: 10px" @click="disconnect">disconnect</div>
  </div>
</template>
<script>
export default {
  name: "HomeView",
  data() {
    return {
      observer: {},
    };
  },
  mounted() {
    // 可见性发生变化后的回调
    function callback(data) {
      console.log(data[0].target.id);
    }
    // 生成交叉观察器
    this.observer = new IntersectionObserver(callback);
    // 获取目标元素1
    let target1 = document.getElementById("target1");
    // 获取目标元素2
    let target2 = document.getElementById("target2");
    // 监听目标元素1
    this.observer.observe(target1);
    // 监听目标元素2
    this.observer.observe(target2);
  },
  methods: {
    unobserve() {
      let target2 = document.getElementById("target2");
      // 停止监听目标元素2
      this.observer.unobserve(target2)
    },
    disconnect() {
      // 停止监听所有目标元素
      this.observer.disconnect();
    },
  },
};
</script>

代码效果如下所示:

可以看到一开始是监听元素1和元素2,接着停止元素2的监听,最后停止所有元素的监听

加载全部内容

相关教程
猜你喜欢
用户评论