目录

  • 概述
  • MutationObserver 构造函数
  • MutationObserver 的实例方法
  • observe()
  • disconnect(),takeRecords()
  • MutationRecord 对象
  • 应用示例
  • 子元素的变动
  • 属性的变动
  • 取代 DOMContentLoaded 事件
  • 参考链接

重要说明:本教程已经搬迁,此处不再维护,请访问新网址:wangdoc.com/javascript。

概述

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

概念上,它很接近事件,可以理解为 DOM 发生变动就会触发 Mutation Observer 事件。但是,它与事件有一个本质不同:事件是同步触发,也就是说,DOM 的变动立刻会触发相应的事件;Mutation Observer 则是异步触发,DOM 的变动并不会马上触发,而是要等到当前所有 DOM 操作都结束才触发。

这样设计是为了应付 DOM 变动频繁的特点。举例来说,如果文档中连续插入1000个<p>元素,就会连续触发1000个插入事件,执行每个事件的回调函数,这很可能造成浏览器的卡顿;而 Mutation Observer 完全不同,只在1000个段落都插入结束后才会触发,而且只触发一次。

Mutation Observer 有以下特点。

  • 它等待所有脚本任务完成后,才会运行(即异步触发方式)。
  • 它把 DOM 变动记录封装成一个数组进行处理,而不是一条条个别处理 DOM 变动。
  • 它既可以观察 DOM 的所有类型变动,也可以指定只观察某一类变动。

MutationObserver 构造函数

使用时,首先使用MutationObserver构造函数,新建一个观察器实例,同时指定这个实例的回调函数。

var observer = new MutationObserver(callback);

上面代码中的回调函数,会在每次 DOM 变动后调用。该回调函数接受两个参数,第一个是变动数组,第二个是观察器实例,下面是一个例子。

var observer = new MutationObserver(function (mutations, observer) {mutations.forEach(function(mutation) {console.log(mutation);});
});

MutationObserver 的实例方法

observe()

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

  • 第一个参数:所要观察的 DOM 节点
  • 第二个参数:一个配置对象,指定所要观察的特定变动
var article = document.querySelector('article');var  options = {'childList': true,'attributes':true
} ;observer.observe(article, options);

上面代码中,observe方法接受两个参数,第一个是所要观察的DOM元素是article,第二个是所要观察的变动类型(子节点变动和属性变动)。

观察器所能观察的 DOM 变动类型(即上面代码的options对象),有以下几种。

  • childList:子节点的变动(指新增,删除或者更改)。
  • attributes:属性的变动。
  • characterData:节点内容或节点文本的变动。

想要观察哪一种变动类型,就在option对象中指定它的值为true。需要注意的是,必须同时指定childListattributescharacterData中的一种或多种,若未均指定将报错。

除了变动类型,options对象还可以设定以下属性:

  • subtree:布尔值,表示是否将该观察器应用于该节点的所有后代节点。
  • attributeOldValue:布尔值,表示观察attributes变动时,是否需要记录变动前的属性值。
  • characterDataOldValue:布尔值,表示观察characterData变动时,是否需要记录变动前的值。
  • attributeFilter:数组,表示需要观察的特定属性(比如['class','src'])。
// 开始监听文档根节点(即<html>标签)的变动
mutationObserver.observe(document.documentElement, {attributes: true,characterData: true,childList: true,subtree: true,attributeOldValue: true,characterDataOldValue: true
});

对一个节点添加观察器,就像使用addEventListener方法一样,多次添加同一个观察器是无效的,回调函数依然只会触发一次。但是,如果指定不同的options对象,就会被当作两个不同的观察器。

下面的例子是观察新增的子节点。

var insertedNodes = [];
var observer = new MutationObserver(function(mutations) {mutations.forEach(function(mutation) {for (var i = 0; i < mutation.addedNodes.length; i++)insertedNodes.push(mutation.addedNodes[i]);})
});
observer.observe(document, { childList: true });
console.log(insertedNodes);

disconnect(),takeRecords()

disconnect方法用来停止观察。调用该方法后,DOM 再发生变动,也不会触发观察器。

observer.disconnect();

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

observer.takeRecords();

下面是一个例子。

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

MutationRecord 对象

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

MutationRecord对象包含了DOM的相关信息,有如下属性:

  • type:观察的变动类型(attributecharacterData或者childList)。
  • target:发生变动的DOM节点。
  • addedNodes:新增的DOM节点。
  • removedNodes:删除的DOM节点。
  • previousSibling:前一个同级节点,如果没有则返回null
  • nextSibling:下一个同级节点,如果没有则返回null
  • attributeName:发生变动的属性。如果设置了attributeFilter,则只返回预先指定的属性。
  • oldValue:变动前的值。这个属性只对attributecharacterData变动有效,如果发生childList变动,则返回null

应用示例

子元素的变动

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

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);}}}}// 对外暴露readywin.ready = ready;})(this);ready('.foo', function(element){// ...
});

参考链接

  • Paul Kinlan, Detect DOM changes with Mutation Observers
  • Tiffany Brown, Getting to know mutation observers
  • Michal Budzynski, JavaScript: The less known parts. DOM Mutations
  • Jeff Griffiths, DOM MutationObserver – reacting to DOM changes without killing browser performance
  • Addy Osmani, Detect, Undo And Redo DOM Changes With Mutation Observers
  • Ryan Morr, Using Mutation Observers to Watch for Element Availability

转载于:http://javascript.ruanyifeng.com/dom/mutationobserver.html

MutationObserver api相关推荐

  1. JavaScript是如何工作的:使用MutationObserver跟踪DOM的变化

    摘要: 掌握MutationObserver. 原文:JavaScript是如何工作的:使用 MutationObserver 跟踪 DOM 的变化 作者:前端小智 Fundebug经授权转载,版权归 ...

  2. JS实时监听DOM元素变化 - MutationObserver

    使用 MutationObserver API实时监听DOM元素变化 创建 MutationObserver 实列,接受一个用于监听到DOM元素变化的回调函数 const handleListenCh ...

  3. 现代浏览器观察者 Observer API 指南

    前言 前段时间在研究前端异常监控/埋点平台的实现. 在思考方案时,想到了浏览器自带的观察者以及页面生命周期API . 于是在翻查资料时意外发现,原来现代浏览器支持多达四种不同类型的观察者: Inter ...

  4. 基于指令和混合的前端通用埋点方案

    https://zhuanlan.zhihu.com/p/27659302 摘要 本文介绍了一种通用的前端埋点方案的设计和实现,具有适配项目广泛,易于使用,与业务逻辑解耦等优点,已经在外卖商业平台进行 ...

  5. web record 前端页面录屏 (react + typescript)

    web record 前端页面录屏 (react + typescript + parcel) 项目地址: https://github.com/bgwd666/web-record 演示: 录屏页面 ...

  6. FlutterWeb性能优化探索与实践

    点击"开发者技术前线",选择"星标" 让一部分开发者看到未来 来自:美团技术团队 美团外卖商家端基于 FlutterWeb 的技术探索已久,目前在多个业务中落地 ...

  7. lsdyna如何设置set中的node_list_如何监视 DOM 树的变动?

    在某些场景下,我们希望能监视 DOM 树的变动,然后做一些相关的操作.比如监听元素被插入 DOM 或从 DOM 树中移除,然后添加相应的动画效果.或者在富文本编辑器中输入特殊的符号,如 # 或 @ 符 ...

  8. 宏任务和微任务的详解

    微任务可以在实时性和效率之间做一个有效的权衡. 从目前的情况来看,微任务已经被广泛地应用,基于微任务的技术有 MutationObserver.Promise 以及以 Promise 为基础开发出来的 ...

  9. 精学JS:宏任务 微任务的运行机制

    首先分析宏任务和微任务的运行机制,并针对日常开发中遇到的各种宏任务&微任务的方法,结合一些例子来看看代码运行的顺序逻辑,把这部分知识点重新归纳和梳理.   在日常开发中,例如 setTimeo ...

最新文章

  1. java 安装界面广告_用javascript实现仿163的js广告向下挤压页面的效果
  2. 出现了奇数次的数字的算法
  3. centos7挂载nas存储_Geeki说丨浅谈几种存储添加主机映射方式
  4. 这些面试细节90%的人都没注意!怪不得简历白投了...
  5. Julia: 关于下载库时WinRPM的Bug
  6. c/c++中与字符串处理相关的函数
  7. 人大金仓数据库 Windows安装教程 -kingbase8R6
  8. 【GamePlay】Unity手机屏幕UI适配问题
  9. python处理word文档中的某页_Python快速设置Word文件中指定段落为目录标题
  10. coso js 魔窗
  11. 骨传导耳机会伤害耳朵吗?骨传导耳机优点是什么
  12. 还在用Evernote或印象笔记吗?来看看笔记神器Notion吧!
  13. 图解通信原理与案例分析-29:埃隆.马斯克的“星链”Starlink计划是卫星语音通信向卫星互联网的演进
  14. 值得收藏的机器学习资源
  15. 2008无线站点、客户端、手游TOP50揭晓!
  16. SVN在Eclipse中的安装步骤以及使用方法和建立分支
  17. 客观赋权法的python实现
  18. pdf.js的使用(C#后台返回pdf文件流)
  19. 抓住人性的套路出牌,实现利益的最大化
  20. 体温单开发_产品开发可以从我们的体温调节系统中学到什么?

热门文章

  1. DDR4的内存计算方法
  2. 第一次软件工程作业--心理测试系统
  3. linux不同用户环境变量问题
  4. 2005新年健康生活大排雷
  5. 帧、报文、报文段、分组、包、数据报的概念区别
  6. IE浏览器打开ie模式
  7. Android编译详解之lunch命令
  8. 基于单片机智能睡眠枕整套设计方案
  9. some problem
  10. rabitMQ work模式二 按能力分配任务