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删除处理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容

  • 导语:前段时间做某系统审核后台,出现了审核人员截图把内容外泄露的情况,虽然截图内容不是特别敏感,但是安全问题还是不...
    李亚_45be阅读 1,180评论 0 0
  • #JavaScript best practices JS最佳实践## 0 简介> 最佳实践起初比较棘手,但最终会...
    yanlee26阅读 653评论 0 1
  • MutationObserver接口提供了监视对DOM树所做更改的能力。它被设计为旧的Mutation Event...
    wwmin_阅读 2,890评论 0 52
  • 一、概念介绍 Vue.js和React.js分别是目前国内和国外最火的前端框架,框架跟类库/插件不同,框架是一套完...
    刘远舟阅读 1,035评论 0 0
  • 前言开门见山,这篇文章,适合 「 初级前端 」 ,如果你还在校招的话,或者还在求职的话,可以看看本文,找一找灵感,...
    WEB前端含光阅读 1,339评论 1 2