IntersectionObserver, ResizeObserver, MutationObserver总结介绍

IntersectionObserver

提供了一套异步检测目标元素与祖先元素或 viewport 相交情况变化的方法。如果不兼容,需要使用 Element.getBoundingClientRect() 方法去获取相对位置,外加 scroll 事件监听去实现对应的功能。

使用场景
  • 图片懒加载:当图片滚动到可见时才进行加载;
  • 内容无限滚动:也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉;
  • 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况;
  • 在用户看见某个区域时执行任务或播放动画;
回调函数触发的时机
  • 每当目标 (target) 元素与设备视窗或者其他指定元素 发生交叉 的时候执行。设备视窗或者其他元素我们称它为根元素或根 (root);
  • Observer 第一次监听目标元素的时候, 初始化也需要判断是否有交叉部分;
  • 回调函数将会被当作任务(也称作 宏任务)增加到主线程的消息队列中等待执行;
配置属性
  • root:指定根 (root) 元素,用于检查目标的可见性。必须是目标元素的父级元素。如果未指定或者为null,则默认为浏览器视窗;
  • rootMargin: 根 (root) 元素的外边距。类似于 CSS 中的 margin 属性,比如 “10px 20px 30px 40px” (top, right, bottom, left)。如果有指定 root 参数,则 rootMargin 也可以使用百分比来取值。该属性值是用作 root 元素和 target 发生交集时候的计算交集的区域范围,使用该属性可以控制 root 元素每一边的收缩或者扩张。默认值为 0, 如果想要 target 元素还没真正交叉的时候触发,可以通过这个值来调节,也就是说,可以设置在外边距多少范围内也可以触发;
  • threshold: 可以是单一的 number 也可以是 number 数组,target 元素和 root 元素相交程度达到该值的时候 IntersectionObserver 注册的回调函数将会被执行。如果你只是想要探测当 target 元素的在 root 元素中的可见性超过 50% 的时候,你可以指定该属性值为 0.5。如果你想要 target 元素在 root 元素的可见程度每多 25% 就执行一次回调,那么你可以指定一个数组 [0, 0.25, 0.5, 0.75, 1]。默认值是 0 (意味着只要有一个 target 像素出现在 root 元素中,回调函数将会被执行)。该值为 1.0 含义是当 target 完全出现在 root 元素中时候 回调才会被执行。
停止某个观察对象或者取消所有观察
  • unobserve: 方法入参对应的 target 元素可取消观察;
  • disconnect:方法只要调用便会取消所有的观察;
注意事项

注册的回调函数将会在主线程中被执行,回调任务将在浏览器空闲的时候被增加在任务队列中等待执行, 如果耗时操作会使得当前任务占用时间过长,造成卡顿。所以该函数执行速度要尽可能的快。如果有一些耗时的操作需要执行,建议使用 Window.requestIdleCallback() 方法。

代码示例
<body>
  <div style="height: 300px;background-color: #f7f7f7;" class="div-1">1</div>
  <div style="height: 300px;" class="div-2">2</div>
  <div style="height: 300px;" class="div-3">3</div>
  <div style="height: 300px;background-color: #f7f7f7;" class="div-4">4</div>
</body>
<script>
  function intersectionExecFunc(infos, intersectionOpts) {
    infos.forEach(info => {
      /**
       * Each info describes an intersection change for one observed target element:
       * info 描述每一个被观察元素的交叉信息的改变
       */

      /** 绑定元素矩形区域信息, 包括 x, y, width, height, top, left, right, bottom */
      console.log('boundingClientRect', info.boundingClientRect);
      /** 交叉比例, 也可以理解为与父级的交叉部分比例 */
      console.log('intersectionRatio', info.intersectionRatio);
      /** 交叉部分区域信息 */
      console.log('intersectionRect', info.intersectionRect);
      /** 是否满足 threshold 设定的交叉比例 */
      console.log('isIntersecting', info.isIntersecting);
      /** 对应的设置的父元素的矩形区域信息 */
      console.log('rootBounds', info.rootBounds);
      // console.log(info.target);
      /** 交叉的时间, 对比时间为实例化的时间 */
      console.log('time', info.time);

      console.log('~~~~~~~~~~~~');
    });
  };

  const intersectionOption = {
    // root: document.querySelector('.div-4'),
    /** 触发方法的临界值, 当达到这个交叉比例时触发, 如果是一个数组, 那么在对应的临界点便触发, 取值在 0.0 和 1.0 之间 */
    threshold: 0.5,
  };

  const intersection = new IntersectionObserver(intersectionExecFunc, intersectionOption);

  /** 创建的交叉观察对象可观察多个是否可见的元素 */
  intersection.observe(document.querySelector('.div-3'));
  intersection.observe(document.querySelector('.div-4'));

  /** 可解除对应元素的观察 */
  // intersection.unobserve(document.querySelector('.div-3'));

  /** 停止所有的观察 */
  // intersection.disconnect();
</script>

如上所示,创建的观察实例可以观察多个元素。

ResizeObserver

提供了一种高性能的机制,通过该机制,代码可以监视元素的大小更改,并且每次大小更改时都会向观察者传递通知。比如 Element 内容盒或边框盒及 SVGElement 边界尺寸的变化。注意, 初始化的时候会触发一次。

使用介绍

如下简要使用示例, 实际使用中, 如果监听了某个元素的变动, 一定要调用 unobserve 取消某个元素的监听 或者 调用 disconnect() 取消所有元素的监听, 以免造成性能问题

  const resizeObserver = new ResizeObserver((entries, resizeOb) => {
    /* 如果监听多个这里就是多项 **/
    for (const entry of entries) {
      console.log(entry);

      /* Firefox 实现的 contentBoxSize 是一个单项值, 并非数组 **/
      const contentBoxSize = Array.isArray(entry.contentBoxSize)
        ? entry.contentBoxSize[0]
        : entry.contentBoxSize;

      console.log(contentBoxSize);
    }
    /* 在内部也能直接取到实例, 对其进行操作, 比如取消监听 **/
    console.log('对应的实例 =>', resizeOb);
  });

  /* 假设页面中有某个元素 **/
  const divEl = document.querySelector('.container');
  /* 监听页面中某个元素 **/
  resizeObserver.observe(divEl);

  /* 取消某个监听 **/
  // resizeObserver.unobserve(divEl);

  /* 取消全部监听 **/
  // resizeObserver.disconnect();

observe 方法支持两个参数:

observe(target, options);
  • target: 监听的目标
  • options: 目前支持的属性设置
    • box: 可选值有 ‘content-box’ (默认值), ‘border-box’, ‘device-pixel-content-box’;

该种监听方式产生的应该是一个宏任务, 具体可点击查看该实例, https://www.nqone.com/router/do…。通过 performance录制任务执行过程。

MutationObserver

该接口可以监控 DOM 树所做的修改,是旧的 Mutation Events 功能的替代品,该功能是 DOM3 Events 规范的一部分。

简单使用

如下, 监听页面中某个元素, 定义一个按钮点击修改内容和属性, 可以看到打印两个结果, 知道具体修改了哪些内容, 如果不使用了一定要调用 disconnect 方法取消监听。

  /* 假设页面中有该元素 **/
  const el = document.querySelector('.container');

  function mutationObFunc(mutations, paramOb) {
    /*
      * 每一项都是检测到的变动项结果, 可获取相关参数
      * 如果修改多个或者监听多个不同的修改, 就会产生多项
      */
    for (const mutation of mutations) {
      console.log(mutation);
    }

    /* 通过该实例可以取消监听, 做些操作 **/
    console.log('实例对象 =>', paramOb);
  }
  const mutationOb = new MutationObserver(mutationObFunc);

  const observerOptions = {
    /* 观察目标子节点的变化,是否有添加或者删除 **/
    childList: true,
    /* 观察属性变动 **/
    attributes: true,
    /* 观察后代节点,默认为 false **/
    subtree: true,
  };
  mutationOb.observe(el, observerOptions);

  /* 如果不需要了, 停止观察 **/
  // mutationOb.disconnect();

  /* 点击按钮修改属性和内容 **/
  const btn = document.querySelector('.btn');
  btn.addEventListener('click', () => {
    el.innerText = 'q w e r t y';
    el.style.width = '100px';
  });
常用方法:
  • observe: 需要观察的元素, 支持两个参数, 第一个参数对应的元素, 第二个参数为一些配置项;
  • takeRecords: 获取已检测到但尚未由观察者的回调函数处理的所有匹配 DOM 更改的列表,使变更队列保持为空;
  • disconnect: 停止观察变动;

该方式产生的任务应该是一个微任务, 具体示例可点击查看 https://www.nqone.com/…, 通过performance可录制执行过程。

参考文档:

IntersectionObserver观察可视区, https://www.nqone.com…
ResizeObserver观察元素尺寸, https://www.nqone.com…
MutationObserver观察DOM变动, https://www.nqone.com…

  • 21
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值