MutationObserver需显式配置且目标节点必须存在:attributes: true须与childList或characterData共用,否则TypeError;监听class等属性用'class'而非'className',设attributeOldValue:true才获旧值;el.className='x'不触发因改property非attribute;childList可监听增删但删除节点已脱离文档树;subtree:true才能监听深层子节点;非标准属性如_html需改data-html;初始化前变更无法捕获,需手动扫描。

直接说结论:MutationObserver 能监听 DOM 属性和子节点变化,但必须显式配置、目标节点要真实存在、且不能指望它捕获所有“看起来像变化”的操作(比如 el.className = 'x')。
为什么 attributes: true 不触发回调?
常见错误是只写了 attributes: true,却没配 childList: true 或 characterData: true——浏览器会直接抛 TypeError。因为 attributes 选项必须和另外至少一个变更类型共存。
- 确保目标节点是
Element类型(document.getElementById('xxx')返回null就白搭) - 只监听特定属性时,加
attributeFilter: ['class', 'data-status'],注意大小写:是'class',不是'className' - 要拿到旧值,必须同时设
attributeOldValue: true,否则mutation.oldValue是undefined -
el.setAttribute('class', 'x')会触发,el.className = 'x'不会——后者改的是 DOM property,不是 attribute
为什么 childList: true 只监听到新增、看不到删除?
它其实能监听增删,但被删节点已脱离文档树,removedNodes[0].querySelector() 会返回 null,.offsetHeight 是 0,直接读取容易误判或报错。
- 立刻用
Array.from(mutation.removedNodes)缓存引用,别等后续逻辑再访问 - 只监听目标节点的**直接子节点**,深层嵌套(如
#list > .item > span)需开启subtree: true - 确认你观察的是正确父节点:想监
#list的子节点,就observe(document.getElementById('list'), { childList: true }),别去监听document.body然后靠运气
监听自定义属性(如 _html)行不行?
不行。_html 这类非标准属性不会被 attributes: true 捕获,浏览器不把它当合法 HTML attribute 处理。
立即学习“前端免费学习笔记(深入)”;
- 改用标准的
data-前缀:setAttribute('data-html', value),再配attributeFilter: ['data-html'] - 如果必须保留
_html,只能封装 setter,在赋值时手动触发事件或调用observer.takeRecords()+ 主动扫描 - 别试图监听
el._html = value——这是 JS 对象属性,MutationObserver 完全不感知
最常被忽略的一点:监听开始前发生的 DOM 变更,MutationObserver 一概不回溯。哪怕你紧接着就 observe(),之前那一次 appendChild 也永远进不了回调。需要初始化扫描时,得自己手动查一遍目标节点的当前状态。



















