关于本文本文是通过利用生成式 AI 的自动化工作流创建的。我们查阅了 MDN 的 MutationObserver 官方文档,制作了一个教材,用来观察当添加、删除或修改虚拟卡片时会通知什么内容。代码语法虽已核对,但在浏览器中的实际显示效果尚未确认。
验证状态:📘 已核对官方规范与 JavaScript 语法/浏览器和 WordPress 的实际显示尚未确认
JavaScript 是如何知道网页内容发生改变的瞬间的呢?MutationObserver是一个浏览器 API,用于将 HTML 元素增加或属性改变作为变更记录接收。这次我们将亲自触发卡片的变化,并将其与通知日志进行对比。
| 项目 | 本教材的条件 |
|---|---|
| 对象 | 电脑和手机的现代浏览器(未在真机上确认) |
| 技术 | JavaScript 标准的 MutationObserver |
| 费用 | 免费。无需外部库或登录 |
| 输入 | 通过按钮操作虚拟卡片 |
| 通信 | 运行演示时无外部 API 发送 |
| 限制 | 最多 8 张卡片,日志最新 12 行 |
首先运行:增加卡片并查看通知
打开卡片变更监控实时演示(源码已保存至 GitHub。尚未确认是否已反映至 GitHub Pages 以及是否能在实际浏览器中运行)
点击“添加卡片”。
点击“切换首个状态”。
点击“停止监控”,然后再次添加卡片。
预计屏幕上方会显示卡片数量和状态的变化,而下方的“通知日志”则会以文字形式显示所监控到的变更。在第三步中,请注意观察虽然卡片增加了,但通知并没有增加。
操作后请查看此处
| 操作 | 画面的变化 | 通知预测 |
|---|---|---|
| 添加卡片 | 2 张 → 3 张 | 添加:1 张 |
| 切换第一项 | 未完成→已完成 | pending → done |
| 停止监视并添加 | 3张→4张 | 无新通知 |
| 恢复监视并添加 | 4张→5张 | 添加:1张 |
这些是根据代码和API规范预测的结果。并非本次在浏览器中的实际测量。即使恢复监视,停止期间的更改也不会随后集中送达。只有恢复后的新更改才是通知的目标。
点击“删除最后一张卡片”时,列表末尾会减少1张,预计会发出“删除:1张”的通知。“清除日志”只是清除已显示的日志,不会改变卡片列表。
观察技巧卡片发生变化与收到通知是两回事。在监视停止期间卡片也可以被修改。将执行修改的处理与通知修改的处理分开考虑,就能理解其运作机制。
为什么会收到通知
浏览器将页面视为由元素构成的树,称为DOM(文档对象模型)。在本教材中,我们将卡片列表的 ul 元素设为监视对象。按下按钮时,JavaScript会添加元素或更改卡片的 data-state 属性。
flowchart LR A["ボタン操作"] --> B["DOMを変更"] B --> C["MutationObserver"] C --> D["変更記録"] D --> E["通知ログ"]
该图表示概念上的顺序。实际的通知回调不会与DOM修改的处理同步并立即介入,而是在修改后的微任务处理中分发。因此,如果在同一处理中发生多次修改,多个记录可能会合并到一个回调中。通知次数和操作次数不一定相符。
关键代码是此设置
observer.observe(list, {
childList: true,
subtree: true,
attributes: true,
attributeFilter: ["data-state"],
attributeOldValue: true
});
childList 监视元素的添加和删除,attributes 监视属性的更改。subtree 改为 true 后,还可以监视列表子卡片上附加的属性。attributeFilter 仅针对本次所需的 data-state,attributeOldValue 是用于记录更改前值的设置。
但是,subtree: true 可能会将卡片内的文本更新也记录为 childList。最终版将显示为“添加/删除”的记录限定在卡片列表正下方。如果不这样做,仅重写卡片状态标签就可能会被误认为“卡片增加了”。
尝试修改一处
JavaScript最终版中的 attributeOldValue: true 改为 false,然后重新加载页面并点击“切换开头状态”。
| 比较 | 更改前的状态 |
|---|---|
true | 预计记录为 pending |
false | 预计记录为未知 |
无论哪种都可以获取更改后的 done。区别在于“是否连同更改前的值一起包含在通知中”。恢复原样后即可在相同条件下进行比较。
这个实验表明,仅凭事后读取状态是无法恢复“之前是什么”的。根据要监控的信息,事先选择必要的记录非常重要。
运行不正常时
| 症状 | 首先确认 | 处理方法 |
|---|---|---|
| 按钮无响应 | 控制台错误 | app.js 确认加载情况 |
| 通知未增加 | 显示“已停止” | 点击“恢复监控” |
| 无法添加 | 卡片数量 | 如果已有8张请先删除 |
| 更改前状态未知 | attributeOldValue | true还原至 |
| 通知比预期多 | 监控对象与类型 | 排除无关的记录 |
注意MutationObserver 并不是一项用于获取开始监控前历史记录的功能。监控停止期间的更改也无法事后恢复。为了保留重要的操作历史或审计追踪,需要采用其他的存储设计。
在自己的电脑上运行
从 GitHub 的固定提交中将 docs/demos/mutation-observer-card-log/ 里的 index.html 和 app.js 保存到同一个文件夹中,然后在浏览器中打开该 HTML。无需构建、CDN 或外部库。
如果直接打开 HTML 文件无法运行,请在工作文件夹中执行 python3 -m http.server 8000 --bind 127.0.0.1,然后从同一台电脑打开 http://127.0.0.1:8000/。退出方式为 Ctrl+C。不需要管理员权限。另外,这些本地步骤并不意味着本次在实际浏览器中能确认成功。
如果用于工作或学习
在动态添加卡片或通知的屏幕上,有时需要检测“新元素是何时出现的”。例如,当其他 UI 处理向列表中添加行时,为该行附加辅助显示的用途。如果可以直接修改现有的处理,从修改后的函数调用必要的处理有时会更简单。
MutationObserver 可以发现 DOM 的变化,但无法证明业务数据是否正确、是由谁修改的、是否已保存到服务器等内容。请勿将本次仅在屏幕上保留日志的教材用作审计日志或证据保存机制。
监视大量的元素可能会给通知处理带来负担。通过缩小目标元素的范围,用 attributeFilter 仅挑选所需的更改,并用 disconnect() 停止不再需要的监视。本次示例最多为8张卡片,变更日志也限制在12行以内。
为了正确理解被通知的更改而进行的补充实验
MutationObserver 并不会以完全相同的方式通知页面的所有更改。子元素的添加与删除、属性值的更改以及文本的更改属于不同类型的更改。由于在开始监视时需要指定监视对象,因此如果在没有收到通知时,请在断定事件损坏之前,对比监视选项与实际发生更改的位置。添加了卡片的实验与仅更改文字的实验,其记录中显示的内容可能会有所不同。
如果在短时间内发生多次更改,有时会通过一次回调同时接收到多条更改记录。因此,仅凭通知次数与实际添加的卡片数量不一致,并不能说明存在故障。重要的是确认有多少条更改记录以及每条记录的类型是什么。还需要注意的是,在连续进行添加和删除的操作中,最终的视觉效果与中间的更改历史可能会有所不同。
停止监视的操作并不会使屏幕上的卡片本身消失。disconnect() 是用于不再监视后续更改的操作,它与删除已经添加的 DOM 的操作是不同的。如果在停止期间更改了卡片,即使重新开始,过去进行的更改也不一定会自动重新通知。通过对比停止前后的日志,可以明确当前是处于观察什么内容的时期。
在实际业务中使用该 API 时,将监视对象缩小到必要的元素范围内,将更容易排查问题。如果无条件地监视整个页面,可能会大量记录无关的显示更新。在包含个人信息的屏幕上,切勿轻率地将更改内容的全文保存到日志中,还需要采取诸如仅统计更改类型和数量等考量。由于本教材使用的是虚拟卡片,因此在将此注意事项应用到实际的客户屏幕之前,可以先进行评估。
官方资料
官方资料确认:2026年11月2日。除确认 JavaScript 语法外,未确认实际浏览器、GitHub Pages 访问、WordPress 蓝色边框、特色图像、移动端以及打印/PDF 的实际显示效果。
GitHub 示例
MutationObserver 卡片监视教材:README / 演示的 HTML 和 JavaScript
正文负责机制的简短摘录,GitHub 负责完成版和改造步骤。特色图像、发布日期、更新日期、Source/License 交由 WordPress 现有的通用显示处理,不在正文中重复插入。没有在 WordPress 正文中嵌入自定义 CSS 或 JavaScript。
