3

mutationobserver监听dom变化

 1 year ago
source link: https://www.fly63.com/article/detial/12359
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

更新日期: 2023-02-06阅读: 9标签: dom分享

扫一扫分享

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){
  // ...
});

链接: https://www.fly63.com/article/detial/12359


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK