MutationObserver 监听DOM

介绍

MutationObserver接口提供了监视对DOM树所做更改的能力。

构造函数

MutationObserver()创建并返回一个新的MutationObserver它会在指定的DOM发生变化时被调用。

new MutationObserver(callback):当每次DOM发生变化的时候都会触发callback。

等所有的DOM操作完成之后一次执行(异步)

方法
  • disconnect()

    阻止 MutationObserver 实例继续接收的通知,直到再次调用其observe()方法,该观察者对象包含的回调函数都不会再被调用。

  • observe()

    配置MutationObserver在DOM更改匹配给定选项时,通过其回调函数开始接收通知。

  • takeRecords()

    从MutationObserver的通知队列中删除所有待处理的通知,并将它们返回到MutationRecord对象的新Array

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>MutationObserver</title>
</head>
<body>
  <div id="simple" class="test"> simple </div>
</body>
<script>
  // mutations 变动数组 observer 观察器实例
  var observer = new MutationObserver(function (mutations, observer) {
    mutations.forEach(function(mutation) {
      // 执行具体的操作
      // 例如:页面劫持
      console.log(mutation)
    })
  })
  // 开始监听页面根元素 html 变化
  observer.observe(document.getElementById("simple"), {
    attributes: true, // 属性变动
    characterData: true, // 节点内容或节点文本的变动
    childList: true, // 子节点的变动
    subtree: true, // 表示是否将观察器应用于该节点的所有后代节点
    attributeOldValue: true, // 表示观察 attributes 变动时,是否需要记录变动前的属性值
    characterDataOldValue: true, // 表示观察 characterData 变动时,是否需要记录变动前的值
    attributeFilter: ["style"] // 数组,表示需要观察的特定属性 (比如: ["class", "src"])
  });

  // document.getElementById("simple").innerText = 123;
  document.getElementById("simple").firstChild.nodeValue="test";
  // document.getElementById("simple").setAttribute("style", "background-color:blue; color:red; border:1px solid black");
  // document.getElementById("simple").style.height = "123px";
  // document.getElementById("simple").innerHTML = "<p>rrr</p>";
  

  // // 停止观察, 调用该方法后,DOM 再发生变动,也不会触发观察器
  // observer.disconnect();
  // // 清除变动记录,即不再处理未处理的变动,改方法返回变动记录的数组。
  // observer.takeRecords();

  // // 保存所有没有被观察器处理的变动
  // var changes = observer.takeRecords();
  // console.log(changes, "changes");
  // // 停止观察
  // observer.disconnect();

  // MutationRecord 对象
  // type: 观察的变动类型
  // target:发生变动的DOM节点
  // addedNodes:新增的DOM节点
  // removeNodes:删除的DOM节点
  // previousSibling:前一个同级节点,如果没有则返回null
  // nextSibling:下一个同级节点,如果没有则返回null
  // attributeName:发生变动的属性。如果这只了 attributeFilter,则只返回预先指定的属性
  // oldValue:变动前的值。这个属性只对 attribute和characterData变动有效,如果发生childList变动,则返回null
</script>
</html>

示例:水印不可删

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="content"></div>
</body>
<script>
  function drawCanvas() {
    let content = document.getElementById("content");
    let divContainer = document.body.appendChild(document.createElement('div'));
    content.appendChild(divContainer);
    let waterMarkercanvas = document.createElement('canvas');
    let context = waterMarkercanvas.getContext('2d');

    divContainer.appendChild(waterMarkercanvas);
    divContainer.id = 'divContainer'
    let backgroundUrl = null;

    divContainer.style.height = window.innerHeight + 'px';
    divContainer.style.width = window.innerWidth + 'px';


    waterMarkercanvas.width = "400";
    waterMarkercanvas.height = "400";

    context.font = "20px";
    context.textAlign = "center";
    context.fillStyle = "#0000ff";

    context.fillText("我是水印", 100, 100);

    backgroundUrl = waterMarkercanvas.toDataURL('image/png');
    divContainer.style.backgroundImage = `url(${backgroundUrl})`;
  }
  drawCanvas();
  let callback = (mutations) => {
    mutations.forEach(mutation => {
        console.log(mutation,"mutation");
        if(mutation.removedNodes.length > 0 && mutation.removedNodes[0].id == "divContainer" && mutation.addedNodes.length <= 0) {
          setTimeout(function() {
            console.log("新增")
            drawCanvas();
          }, 3000)
        }
    });
  };
  let observer = new MutationObserver(callback);
  observer.observe(document.getElementById("content"), {
    childList: true,
    // subtree: true
  });
  console.log(document.getElementsByTagName("div"))
  setTimeout(function() {
    console.log("删除")
    document.getElementById("content").removeChild(document.getElementById("divContainer"));
  }, 3000)
</script>
</html>

 

  • 防止运营劫持:监控dom,不在白名单内和安全标签内的script或者iframe,都给予remove删除处理。



作者:带刀打天下
链接:https://www.jianshu.com/p/7129ce865f33
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
posted @ 2022-08-09 18:49  小猪冒泡  阅读(421)  评论(0编辑  收藏  举报