mutationobserver 监听 textcontent 变化最可靠,需同时设置 subtree: true 和 characterdata: true,必要时加 childlist: true;不能监听伪元素内容,ie11 需降级轮询。

MutationObserver 监听 textContent 变化最可靠
直接用 MutationObserver 监听 characterData 类型变动,是当前唯一稳定捕获 DOM 文本内容修改的方式。旧的 DOMCharacterDataModified 事件早已被主流浏览器废弃,硬写只会静默失效。
常见错误现象:监听了 div 元素却收不到 innerText 改变;手动调用 el.textContent = 'x' 后回调没触发;Vue/React 更新后监听丢失。
- 必须把
subtree: true和characterData: true同时设为true,否则只监听顶层文本节点,子节点改了也不报 - 如果目标元素是
contenteditable或含富文本,需额外监听childList: true,因为用户输入可能插入新textNode而非修改旧节点 - 不要监听
textContent属性本身——它不是可观察的属性,DOM 没有“属性变更事件”机制
为什么不用 DOMSubtreeModified 或 input 事件
DOMSubtreeModified 在 Chrome 55+、Firefox 60+ 已被移除,且性能极差,会频繁触发并阻塞渲染;input 事件只适用于 input/textarea,对 div[contenteditable] 支持不一致,更无法覆盖 JS 主动修改文本的场景。
使用场景举例:div 实时渲染 Markdown 预览、后台自动注入日志文本、第三方脚本动态改文案需拦截。
立即学习“前端免费学习笔记(深入)”;
-
input事件在 Safari 中对contenteditable触发不全,尤其粘贴或格式化操作 -
MutationObserver回调中不能直接再改同一节点的文本,否则可能引发无限循环(需加防抖或标记位) - IE11 不支持
MutationObserver,如需兼容,只能降级用轮询el.textContent(间隔 ≥ 100ms,避免卡顿)
监听前必须确保文本节点存在
很多人监听失败,是因为目标元素下根本没有 Text 节点——比如空 div、仅含注释或元素节点时,characterData 根本不会触发。
实操建议:用 el.childNodes 检查是否存在 nodeType === 3 的节点;若不确定结构,先用 childList: true 捕获新增文本节点,再对新节点单独 observe。
- 初始化时主动调用一次
observer.takeRecords()+ 手动比对初始textContent,避免漏掉首次渲染的文本 - 避免监听
document.body这类大范围节点,性能损耗明显,应精确到最小父容器 - React/Vue 组件内使用时,务必在
useEffect或mounted中启动,在unmounted或清理函数中调用observer.disconnect()
简单可用的最小监听模板
以下代码能覆盖 90% 的文本监听需求,不含冗余逻辑,可直接嵌入项目:
const observer = new MutationObserver(mutations => {
mutations.forEach(m => {
if (m.type === 'characterData' && m.target.nodeType === 3) {
console.log('文本变了:', m.target.textContent);
}
});
});
observer.observe(targetEl, {
subtree: true,
characterData: true,
childList: true
});
注意:m.target 是被修改的 Text 节点,不是父元素;targetEl 必须是已挂载的 DOM 节点,不能是字符串或未 append 的元素。
容易被忽略的一点:如果文本内容由 CSS ::before/::after 伪元素生成,MutationObserver 完全无法监听——那属于样式层,不在 DOM 树中。











