mutationobserver 监听属性变化需同时设置 attributes: true 与 childlist: true 或 characterdata: true,仅监听 html attribute(如 data-*),须用 attributefilter 限定属性、attributeoldvalue: true 获取旧值,subtree: true 才能捕获深层变更,回调为微任务,批量合并触发且不阻塞主线程。

要监听属性变化,MutationObserver 必须显式开启 attributes: true,且不能单独使用——它必须和 childList: true 或 characterData: true 至少一项共存,否则会直接抛出 TypeError。它监听的是 HTML attribute(如 class、data-id、aria-expanded),不是 DOM property(比如 el.className = 'x' 或 el.style.color = 'red' 不触发)。
只监听关键属性,避免干扰
画布中 class、style 频繁变动但多数无需响应,用 attributeFilter 锁定真正有意义的属性:
- 写成
attributeFilter: ['data-component-id', 'data-props', 'data-status'],注意是字符串数组,用小写属性名('class'✅,不是'className'❌) -
data-*类属性最稳妥:无论用setAttribute('data-id', '123')还是el.dataset.id = '123'都会触发 - 想比对新旧值(比如判断是否从
data-status="loading"变为"success"),必须加attributeOldValue: true,否则mutation.oldValue永远是undefined
监听范围要配对:subtree 决定能否捕获深层变更
如果目标节点本身属性没变,但它的子节点(甚至孙节点)被动态插入并带了你要监听的属性(例如框架注入的 data-loaded="true"),仅设 attributes: true 是不够的:
- 只监听目标元素自身属性 →
subtree: false(默认)即可 - 要捕获整个画布区域(如
#canvas-container)内任意层级的属性变更 → 必须同时设subtree: true和attributes: true - 别指望
document.body当万能目标:旧版 Safari 不稳定,推荐观察具体容器节点
微任务触发逻辑:批量、异步、不阻塞
MutationObserver 的回调不是同步执行,也不是宏任务,而是推入微任务队列,在当前 JS 执行栈清空后、渲染前立即运行:
- 连续 5 次
setAttribute,浏览器会合并为一次回调,mutations数组含 5 条记录,便于批量去重和统一处理 - 它属于防抖式响应:短时间高频变动不会反复打断主线程,拖拽、缩放等交互依然流畅
- 回调里访问 DOM 状态(如
offsetHeight)是安全的,但若需读取 layout(如尺寸、位置),建议包裹requestAnimationFrame以确保样式已计算完毕 - 所有监听逻辑都在微任务中完成,不影响用户操作的实时性,也天然适配低代码画布这类动态频繁的场景











