【Web API】MutationObserver

188 阅读2分钟

按照惯例,先看下MDN的介绍: MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Events功能的替代品,该功能是DOM3 Events规范的一部分。

可以看到这个接口的作用是在DOM树修改之后提供了一个异步回调,方便用户自己处理DOM批量修改后的操作。因为是异步的,所以它会在所有DOM操作修改完后才调用回调方法,从而减少了调用次数。和事件不一样,事件是同步的。看下下面的一个例子:

<html>
<head></head>
<body>
  <p id="pid" onclick="handler()">ywdong测试一下</p>
  <script>
    window.onload = function() {
      // 选择需要观察变动的节点
      var targetNode = document.querySelector('#pid')

      // 观察器的配置(需要观察什么变动)
      var config = { attributes: true, childList: true, subtree: true };

      // 当观察到变动时执行的回调函数
      var callback = function(mutationsList, observer) {
        // 当多次修改dom属性时,下面的console只打印一次
        console.log('trigger callback')
        for(let mutation of mutationsList) {
          if (mutation.type === 'childList') {
            console.log('A child node has been added or removed.');
          } else if (mutation.type === 'attributes') {
            console.log('The ' + mutation.attributeName + ' attribute was modified.');
          } else if (mutation.type === 'subtree') {
            console.log('The subtree was modified.');
          }
        }
      }

      // 创建一个观察器实例并传入回调函数
      window.observer = new MutationObserver(callback);

      // 以上述配置开始观察目标节点
      window.observer.observe(targetNode, config);

      // 之后,可停止观察
      // window.observer.disconnect();
    }

    function handler() {
      var obj = document.querySelector('#pid')
      obj.setAttribute('name', 'testName')
      obj.style.background = 'yellow'
      var childNode = document.createTextNode("child node")
      obj.appendChild(childNode)
    }
  </script>
</body>
</html>

看下点击结果

WechatIMG1.jpeg

上面那个例子可以看到,我们多次修改了元素的属性,且新增了一个节点,但callback方法只执行了一次。如果每次修改都要执行回调的话,会显得效率很低下了。

config或者叫观察器的配置提供了以下几种,可以根据自身需要取不同的配置:

配置项是否可选含义
attributeFilter可选要监视的特定属性名称的数组。如果未包含此属性,则对所有属性的更改都会触发变动通知。无默认值。
attributeOldValue可选当监视节点的属性改动时,将此属性设为 true 将记录任何有改动的属性的上一个值。无默认值。
attributes可选设为 true 以观察受监视元素的属性值变更。默认值为 false。
characterData可选设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。无默认值。
characterDataOldValue可选设为 true 以在文本在受监视节点上发生更改时记录节点文本的先前值。无默认值。
childList可选设为 true 以监视目标节点(如果 subtree 为 true,则包含子孙节点)添加或删除新的子节点。默认值为 false。
subtree可选设为 true 以将监视范围扩展至目标节点整个节点树中的所有节点。MutationObserverInit 的其他值也会作用于此子树下的所有节点,而不仅仅只作用于目标节点。默认值为 false。

这个API是在我学习微任务的时候了解的,那么这个时候也就更加了解为什么它是微任务了,因为它跟在UI Render后触发。而UI Render是宏任务。只有当前主线程中的宏任务执行完了才会执行微任务。