资讯动态

JavaScript 标准参考教程:MutationObserver 接口——监听 DOM 变动的异步观察器

发布时间:2026/10/14 6:20:56 来源:尧图企业网站定制
教程文档【免费下载链接】jstutorialJavascript tutorial book项目地址https://gitcode.com/gh_mirrors/js/jstutorial点击查看免费下载Mutation Observer API 是浏览器原生提供的 DOM 变动监听接口用于监控节点的增删、属性变化与文本内容变化。本文是 jstutorial 仓库中 dom/mutationobserver.md 一文的完整展开结合仓库 DOM 模型概述、事件种类 等章节系统讲解 MutationObserver 的构造函数、实例方法、MutationRecord 记录对象并给出可直接运行的实战示例。读完本文你将掌握如何用 MutationObserver 监听页面任何位置的 DOM 变动、读取变动详情以及用其替代DOMContentLoaded事件实现元素出现即回调的通用封装。概述为什么需要 Mutation ObserverMutation Observer API 用来监视 DOM 变动。DOM 的任何变动比如节点的增减、属性的变动、文本内容的变动这个 API 都可以得到通知。在 jstutorial 的 DOM 模型概述 中已经介绍过浏览器会根据 DOM 模型将 HTML 解析成节点树DOM TreeDocument、Element、Text、Attribute等都是不同类型的节点而 Mutation Observer 正是监听这棵节点树上任何结构或内容变化的接口。概念上它很接近事件可以理解为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 变动后调用。该回调函数接受两个参数第一个是变动数组由MutationRecord实例组成第二个是观察器实例下面是一个例子。var observer new MutationObserver(function (mutations, observer) { mutations.forEach(function(mutation) { console.log(mutation); }); });回调的mutations参数是一个数组数组中每一项是一条变动记录MutationRecord实例具体结构见后文MutationRecord 对象一节第二个参数observer就是创建它的观察器实例便于在回调中调用disconnect()等方法来停止监听自身。MutationObserver 的实例方法MutationObserver实例提供三个方法observe()启动监听、disconnect()停止监听、takeRecords()取出并清空未处理的变动记录。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节点内容或节点文本的变动。想要观察哪一种变动类型就在options对象中指定它的值为true。需要注意的是必须同时指定childList、attributes和characterData中的一种或多种若均未指定将报错。除了变动类型options对象还可以设定以下属性subtree布尔值表示是否将该观察器应用于该节点的所有后代节点attributeOldValue布尔值表示观察attributes变动时是否需要记录变动前的属性值characterDataOldValue布尔值表示观察characterData变动时是否需要记录变动前的值attributeFilter数组表示需要观察的特定属性比如[class,src]。下面是一个同时启用全部观察选项的例子监听文档根节点即html标签的所有变动// 开始监听文档根节点即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);这里把监听目标直接设为document整个文档配置只打开childList因此文档中任何位置新增子节点都会被记录进mutation.addedNodes中。disconnect() 与 takeRecords()disconnect方法用来停止观察。调用该方法后DOM 再发生变动也不会触发观察器。observer.disconnect();takeRecords方法用来清除变动记录即不再处理未处理的变动。该方法返回变动记录的数组。observer.takeRecords();下面是一个将两者组合使用的典型场景// 保存所有没有被观察器处理的变动 var changes mutationObserver.takeRecords(); // 停止观察 mutationObserver.disconnect();需要留意的是disconnect()只是解除观察器的监听此前已经产生、但尚未交付给回调函数的变动记录会保留在内部队列中如果希望连这些积压记录也一并取走就需要先用takeRecords()取出该方法会返回并清空队列再调用disconnect()。这也是上面示例把takeRecords()放在disconnect()之前的原因。MutationRecord 对象DOM 每次发生变化就会生成一条变动记录MutationRecord实例。该实例包含了与变动相关的所有信息。Mutation Observer 处理的就是一个个MutationRecord实例所组成的数组。MutationRecord对象包含了 DOM 的相关信息有如下属性type观察的变动类型attribute、characterData或者childListtarget发生变动的 DOM 节点addedNodes新增的 DOM 节点removedNodes删除的 DOM 节点previousSibling前一个同级节点如果没有则返回nullnextSibling下一个同级节点如果没有则返回nullattributeName发生变动的属性。如果设置了attributeFilter则只返回预先指定的属性oldValue变动前的值。这个属性只对attribute和characterData变动有效如果发生childList变动则返回null。其中type的取值与observe()配置中的观察类型一一对应oldValue只有在配置了attributeOldValue: true观察属性变动或characterDataOldValue: true观察文本变动时才会有实际值。这样设计的好处是回调函数可以根据type字段分流处理不同类别的变动也可以从oldValue中实现变动前后对比例如实现撤销功能。应用示例子元素的变动下面的例子说明如何读取变动记录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表示观察后代节点的变动。回调函数会在控制台显示所有变动的类型和目标节点。subtree: true让观察范围从body自身扩展到其全部后代节点因此body内部任何层级的子节点增删都会进入变动记录。属性的变动下面的例子说明如何追踪属性的变动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然后设定记录变动前的值attributeOldValue: true。实际发生变动时会将变动前的值显示在控制台。这里oldValue只有在打开attributeOldValue时才有意义如果只配置attributes: true而没有attributeOldValuerecord.oldValue会是null。取代 DOMContentLoaded 事件网页加载的时候DOM 节点的生成会产生变动记录因此只要观察 DOM 的变动就能在第一时间触发相关事件因此也就没有必要使用DOMContentLoaded事件。var observer new MutationObserver(callback); observer.observe(document.documentElement, { childList: true, subtree: true });上面代码中监听document.documentElement即html节点的子节点的变动subtree属性指定监听还包括后代节点。因此任意一个网页元素一旦生成就能立刻被监听到。作为对照jstutorial 的 事件种类 一章介绍过DOMContentLoaded事件在网页下载并解析完成以后在document对象上触发此时整张页面的 DOM 已经生成但外部资源样式表、脚本、iframe 等可能还没有下载结束jQuery 教程 中的$(document).ready()方法本质上就是DOMContentLoaded事件的回调。而 Mutation Observer 的监听方式比事件更细粒度事件只通知整个文档解析完成这一时间点Observer 则能捕获从首个节点开始生成、到整棵 DOM 树构建完成的每一个变动瞬间而且不依赖脚本是否堵塞。下面的代码使用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){ // ... });这段封装代码体现了 Mutation Observer 的典型工程用法值得拆解几个关键设计兼容前缀win.MutationObserver || win.WebKitMutationObserver兼容旧版 WebKit 内核浏览器现代浏览器普遍直接支持MutationObserver前缀写法仅为历史兼容观察器惰性创建只有第一次调用ready()时才创建观察器并监听document.documentElement的childListsubtree变动后续调用直接复用元素去重通过在元素上挂载element.ready标记确保同一个元素只触发一次回调即使它多次匹配选择器立即检查每次注册时先调用一次check()如果目标元素在注册时已经存在于 DOM 中也能立刻触发回调而不必等待下一次变动。这种监听 DOM 生成的通用封装正好解决了传统DOMContentLoaded/$(document).ready()的痛点当目标元素是脚本动态注入、或加载时序不确定时例如异步组件渲染完成后才出现的节点事件机制无法预知其出现时机而 Mutation Observer 可以在元素出现的瞬间精准触发回调。小结Mutation Observer 是处理 DOM 动态变动的首选接口。与同步事件不同它以异步、批量的方式处理变动记录天然适合频繁 DOM 操作的场景observe()的childList、attributes、characterData三类观察维度加上subtree、attributeOldValue、characterDataOldValue、attributeFilter等配置项让开发者可以精确控制监听范围与记录粒度MutationRecord则提供了type、target、addedNodes、removedNodes、oldValue等完整信息支撑变动追踪、元素就绪检测、撤销重做等高级应用。结合本仓库 DOM 模型概述 中关于节点树的知识以及 事件种类 中对DOMContentLoaded与readystatechange事件的讲解可以更全面地理解 Mutation Observer 在整个 DOM 编程体系中的位置与适用场景。赞分享教程文档【免费下载链接】jstutorialJavascript tutorial book项目地址https://gitcode.com/gh_mirrors/js/jstutorial点击查看免费下载相关推荐现代 JavaScript 教程MutationObserver 深入解析 —— DOM 变动观察器的语法、用例与实战现代 JavaScript 教程MutationObserver 深入解析 —— DOM 变动观察器的语法、用例与实战 MutationObserver 是浏文档教程JavaScript 如何用 MutationObserver 监听 DOM 节点与属性变化JavaScript 如何用 MutationObserver 监听 DOM 节点与属性变化 当页面上的变化来自你不控制的代码时——第三方脚本往容器里插入元素、教程前端文档用 Rufus 把整块磁盘打包成镜像文件VHD、VHDX、FFU 三种方案一次讲透用 Rufus 把整块磁盘打包成镜像文件VHD、VHDX、FFU 三种方案一次讲透 RufusThe Reliable USB Formatting Uti桌面应用开发工具上一篇没有独显的 2015 旧本也能离线跑大模型GPT4All 与 5 款本地 LLM 工具 3 天实测下一篇如何快速集成fuubar进度条与调试工具Pry和Byebug的终极指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑