要实时监听dom变化,mutationobserver必须同时启用childlist、attributes和characterdata,并正确配置target、subtree、attributefilter等选项;需显式调用observe(),注意避免死循环、内存泄漏及高频回调问题。
要实时监听 dom 树的结构变化、属性变更与文本修改,mutationobserver 必须同时启用 childlist、attributes 和 characterdata 三项配置,并正确设置目标节点和辅助选项。它不是“开箱即用”,而是需要明确告诉浏览器:你关心哪类变化、在哪个节点上、是否深入后代、要不要旧值。
监听结构变化:子节点增删与深层嵌套
结构变化主要指元素被添加、移除或重排,对应 mutation.type === 'childList'。
- 必须设
childList: true,否则完全收不到节点增删通知 - 若变化发生在目标节点的孙子、曾孙层级(如
#app > .content > ul > li),仅靠childList不够,需额外加subtree: true - 目标节点必须是已挂载的真实 DOM 元素(
nodeType === 1),不能是null或尚未插入文档的临时节点 -
addedNodes和removedNodes是只读 NodeList,建议立即转为数组处理:Array.from(mutation.addedNodes)
监听属性变更:class、style、data-* 等动态修改
属性变化触发 mutation.type === 'attributes',但有严格前提:
-
attributes: true必须与childList: true或characterData: true至少一项共存,否则会报错 - 只对 Element 节点生效,Text、Comment、Document 节点不响应
- 想只监听特定属性(如
class或data-status),加上attributeFilter: ['class', 'data-status'] - 需要对比新旧值?必须配
attributeOldValue: true,旧值存在mutation.oldValue中,新值需通过target.getAttribute(attrName)获取
监听文本修改:textContent 或 innerText 的动态更新
文本内容变动(如倒计时数字、状态提示语)属于 characterData 类型,常见于 span、div 等容器内的纯文本节点。
- 启用
characterData: true,并确保目标是文本节点本身(如document.querySelector('#status').firstChild),或其父元素(配合subtree: true) - 要获取修改前的文本,必须同时设
characterDataOldValue: true,旧值在mutation.oldValue,当前值在mutation.target.nodeValue - 注意:直接修改
element.textContent = 'new'会触发;但element.innerHTML = 'new'可能导致整个子树重建,触发childList而非characterData
关键细节与避坑提醒
配置写全了还不够,实际运行中几个细节决定成败:
-
observe() 必须显式调用:仅
new MutationObserver(callback)不会监听,一定要补上observer.observe(target, config) -
回调中改 DOM 易引发死循环:如需自动修复(如移除广告脚本插入的节点),应先
observer.disconnect()→ 执行修改 → 再observer.observe() -
高频变更需节流:某些插件频繁切换 class,可加
setTimeout合并处理,避免回调密集执行 -
组件卸载时务必断开:Vue 的
beforeUnmount、React 的useEffect cleanup中调用observer.disconnect(),防止内存泄漏










