首页 小组 问答 话题 好文 素材 用户 唠叨 我的社区

[教程]mutationobserver监听dom变化

小蜗锅Lv.1普通用户
2024-10-21 17:20:12
0
4

Mutation Observer api 用来监视 dom 变动。DOM 的任何变动,比如节点的增减、属性的变动、文本内容的变动,这个 API 都可以得到通知。

DOM 的变动会触发 Mutation Observer 事件,但与事件不同的是,Mutation Observer 是异步触发,也就是说,Mutation Observer 事件会在所有的 DOM 操作完成后才触发一次。

实例

回调函数接受两个参数,一个是变动的数组,一个是观察器实例

let observer = new MutationObserver(function (mutations, observer) {
  mutations.forEach(function(mutation) {
    console.log(mutation)
  })
  // 返回一个我们监听到的MutationRecord对象
  // MutationRecord对象 是我们每修改一个就会在数组里面追加一个
})

方法

1. observe

observe方法用来启动监听,它接受两个参数

第一个是需要观察的节点

第二个是配置对象,配置项的前三项必须至少设置一项,否则会报错

var container = document.querySelector('.container');

observer.observe(container, {
  childList:true, // 子节点的变动(指新增,删除或者更改)
  attributes:true, // 属性的变动
  characterData:true, // 节点内容或节点文本的变动
  subtree:false, // 是否将该观察器应用于该节点的所有后代节点
  attributeOldValue:false, // 观察attributes变动时,是否需要记录变动前的属性值
  characterDataOldValue:false, // 表示观察characterData变动时,是否需要记录变动前的值
  attributeFilter:[], // 表示需要观察的特定属性,如 ['class','src']
})

2.disconnect

disconnect()方法用来停止观察

3. takeRecords

takeRecords()方法用来清除变动记录,即不再处理未处理的变动。该方法返回变动记录的数组。

可监听的属性(配置)

属性

说明

默认值

attributes

设为 true 以观察受监视元素的属性值变更。

默认值为 false。

attributeFilter

要监视的特定属性名称的数组。如果未包含此属性,则对所有属性的更改都会触发变动通知。

无默认值。

characterData

设为 true 以监视指定目标节点或子节点树中节点所包含的字符数据的变化。

无默认值

childList

设为 true 以监视目标节点(如果 subtree 为 true,则包含子孙节点)添加或删除新的子节点。

默认值为 false。

subtree

的其他值也会作用于此子树下的所有节点,而不仅仅只作用于目标节点。

默认值为 false。

MutationRecord

DOM 每次发生变化,就会生成一条变动记录(MutationRecord 实例)。该实例包含了与变动相关的所有信息。Mutation Observer 返回的第一个参数就是一个个MutationRecord实例所组成的数组。

MutationRecord中包含的信息

  • type:观察的变动类型(attribute、characterData或者childList)。

  • target:发生变动的DOM节点。

  • addedNodes:新增的DOM节点。

  • removedNodes:删除的DOM节点。

  • previousSibling:前一个同级节点,如果没有则返回null。

  • nextSibling:下一个同级节点,如果没有则返回null。

  • attributeName:发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性。

  • oldValue:变动前的值。这个属性只对attribute和characterData变动有效,如果发生childList变动,则返回null。

应用场景:

  • App中用WebView显示一个本地html文件

  • html文件下载JavaScript然后用JSONP显示一个网页

  • 这个网页中实际内容是用iframe显示的一个表单

  • 表单中有一个Close按钮

  • 需求就是点击Close按钮的时候关掉App中引入WebView的页面

简单来说就是想捕捉iframe里面的Close按钮的点击事件。因为捕捉到了点击事件就可以把这个事件传入到App层,App就可以关闭页面。

子元素的变动

下面的例子说明如何读取变动记录。

var callback = function (records){
  records.map(function(record){
    console.log('Mutation type: ' + record.type);
    console.log('Mutation target: ' + record.target);
  });
};

var mo = new MutationObserver(callback);

var option = {
  'childList': true,
  'subtree': true
};

mo.observe(document.body, option);

上面代码的观察器,观察<body>的所有下级节点(childList表示观察子节点,subtree表示观察后代节点)的变动。回调函数会在控制台显示所有变动的类型和目标节点。

属性的变动

下面的例子说明如何追踪属性的变动。

var callback = function (records) {
  records.map(function (record) {
    console.log('Previous attribute value: ' + record.oldValue);
  });
};

var mo = new MutationObserver(callback);

var element = document.getElementById('#my_element');

var options = {
  'attributes': true,
  'attributeOldValue': true
}

mo.observe(element, options);

上面代码先设定追踪属性变动('attributes': true),然后设定记录变动前的值。实际发生变动时,会将变动前的值显示在控制台。

取代 DOMContentLoaded 事件

网页加载的时候,DOM 节点的生成会产生变动记录,因此只要观察 DOM 的变动,就能在第一时间触发相关事件,因此也就没有必要使用DOMContentLoaded事件。

var observer = new MutationObserver(callback);
observer.observe(document.documentElement, {
  childList: true,
  subtree: true
});

上面代码中,监听document.documentElement(即HTML节点)的子节点的变动,subtree属性指定监听还包括后代节点。因此,任意一个网页元素一旦生成,就能立刻被监听到。

下面的代码,使用MutationObserver对象封装一个监听 DOM 生成的函数。

(function(win){
  'use strict';

  var listeners = [];
  var doc = win.document;
  var MutationObserver = win.MutationObserver || win.WebKitMutationObserver;
  var observer;

  function ready(selector, fn){
    // 储存选择器和回调函数
    listeners.push({
      selector: selector,
      fn: fn
    });
    if(!observer){
      // 监听document变化
      observer = new MutationObserver(check);
      observer.observe(doc.documentElement, {
        childList: true,
        subtree: true
      });
    }
    // 检查该节点是否已经在DOM中
    check();
  }

  function check(){
  // 检查是否匹配已储存的节点
    for(var i = 0; i < listeners.length; i++){
      var listener = listeners[i];
      // 检查指定节点是否有匹配
      var elements = doc.querySelectorAll(listener.selector);
      for(var j = 0; j < elements.length; j++){
        var element = elements[j];
        // 确保回调函数只会对该元素调用一次
        if(!element.ready){
          element.ready = true;
          // 对该节点调用回调函数
          listener.fn.call(element, element);
        }
      }
    }
  }

  // 对外暴露ready
  win.ready = ready;

})(this);

ready('.foo', function(element){
  // ...
});
小蜗锅
小蜗锅

1 天前

签名 : 拿人手短,js方面的不懂问我,为了100块钱的赞助豁出去了。   4       0
评论
站长交流