MutationObserver:DOM界的“卧底”,暗中观察每个风吹草动

张开发
2026/5/5 1:23:09 15 分钟阅读
MutationObserver:DOM界的“卧底”,暗中观察每个风吹草动
你想知道页面上的某个元素什么时候被偷偷改了吗比如有个熊孩子脚本悄悄改了你的广告位或者某个懒加载图片终于加载完了今天我们就来请一位“卧底”——MutationObserver让它24小时盯着DOM树任何变化都逃不过它的眼睛。前言假设你开了一家便利店店里装了监控。你想知道什么时候有人进来什么时候货架上的商品被拿走了什么时候价格标签被换了普通的监控只能录像但你需要的是“智能警报”——一有变化就通知你。这就是MutationObserver的活。它是浏览器提供的一个API专门用来监听DOM树的变化节点增删、属性修改、文本内容改变……统统能抓到。而且它不会像setInterval那样一直轮询性能好得多。一、MutationObserver是啥MutationObserver是一个构造函数用来创建一个观察者对象。你可以给它指定一个回调函数然后让它去“盯”某个DOM节点。一旦这个节点或它的子孙节点发生变化回调函数就会被触发。// 创建一个观察者实例传入回调constobservernewMutationObserver((mutationsList,observer){for(letmutationofmutationsList){console.log(mutation.type,发生了变化);}});// 指定要观察的节点consttargetNodedocument.getElementById(watch-me);// 开始观察observer.observe(targetNode,{attributes:true,// 观察属性变化childList:true,// 观察子节点增删subtree:true,// 观察所有后代节点characterData:true// 观察文本内容变化});// 某天不想观察了// observer.disconnect();二、能观察到哪些变化配置选项决定了你关心哪些“风吹草动”attributes属性变了比如class、style、src被改childList子节点被增删添加或删除元素、文本节点characterData文本节点的内容变了subtree是否监听后代节点默认false只监听目标节点attributeFilter只监听特定属性比如[class, src]attributeOldValue是否记录旧属性值characterDataOldValue是否记录旧文本值三、实战监听广告位有没有被篡改很多网站会在页面上放广告但有些恶意脚本会偷偷把广告位换成自己的内容。用MutationObserver可以第一时间发现并报警。dividad-containerimgsrcreal-ad.jpgalt官方广告/divconstadContainerdocument.getElementById(ad-container);constobservernewMutationObserver((mutations){mutations.forEach((mutation){if(mutation.typechildList){// 子节点被改了console.warn(⚠️ 广告位内容被篡改);// 可以上报服务器或者恢复内容}elseif(mutation.typeattributesmutation.attributeNamesrc){console.warn(⚠️ 广告图片被替换了);}});});observer.observe(adContainer,{childList:true,subtree:true,attributes:true,attributeFilter:[src,href]});四、实战监听输入框内容变化代替input事件input事件已经能监听输入框变化但MutationObserver可以监听更底层的文本节点变化比如通过JS直接修改.valueinput事件可能不触发但MutationObserver可以。inputidusernametypetextconstinputdocument.getElementById(username);constobservernewMutationObserver((mutations){mutations.forEach((mutation){if(mutation.typeattributesmutation.attributeNamevalue){console.log(输入框的值被改了新值,input.value);}});});observer.observe(input,{attributes:true,attributeFilter:[value]});注意这种方式监听value属性变化只对通过JS设置.value有效用户手动输入不会触发因为用户输入不改变value属性而是改变元素的defaultValue和内部状态。所以实际中监听输入框还是input事件更合适。这里只是演示能力。五、实战监听动态加载的图片做懒加载很多懒加载库用IntersectionObserver但如果你想知道图片什么时候被添加到DOM可以用MutationObserver。constobservernewMutationObserver((mutations){mutations.forEach((mutation){mutation.addedNodes.forEach((node){if(node.nodeType1node.tagNameIMG){console.log(新图片出现了,node.src);// 可以在这里做懒加载初始化}});});});observer.observe(document.body,{childList:true,subtree:true});六、性能注意事项MutationObserver虽然比轮询好但也不能滥用。以下几点要注意不要观察整个document如果你observe(document.body, { subtree: true, childList: true, attributes: true })那页面上的任何变化都会触发回调频繁执行可能影响性能。尽量把观察范围缩小到具体容器。回调里不要做太重的操作MutationObserver的回调是在微任务中执行的如果里面操作DOM或者计算太多会阻塞后续渲染。及时disconnect如果不再需要观察记得调用disconnect()释放资源。使用takeRecords()在disconnect之前可以调用observer.takeRecords()取出尚未处理的变化记录。七、与旧API对比Mutation Events的悲惨往事很久以前浏览器有一套Mutation Events比如DOMNodeInserted、DOMAttrModified等。它们的问题很多性能差每次变化都同步触发容易导致重入和崩溃不支持批量观察被标记为废弃MutationObserver是它们的完美替代异步、批量、性能好。八、总结MutationObserver就是你的“鹰眼”它能监听DOM树的各种变化属性、子节点、文本内容。配置灵活可以精确到特定属性或是否包含后代。异步回调批量返回变化记录性能优秀。应用场景监听动态内容加载、检测第三方脚本篡改、实现数据绑定比如某些MVVM库的底层、与React/Vue的虚拟DOM配合调试等。有了MutationObserver你就可以在DOM变化时第一时间响应像一个隐形的守护者。明天我们将进入Web Storage的世界看看localStorage、sessionStorage和IndexedDB怎么帮你把数据存到用户浏览器里。如果你觉得今天的“卧底”够犀利点个赞让更多人看到。我们明天见

更多文章