html无原生observer模式,需用javascript实现:mutationobserver监听dom变动,proxy封装对象响应式,eventtarget仅是事件分发机制而非observer模式。

HTML里没有原生Observer模式,得靠JavaScript实现
HTML本身是标记语言,不提供观察者(Observer)机制;所谓“HTML做观察者模式”,实际是指在网页环境中用JavaScript实现Observer逻辑,监听DOM变化、数据变更或自定义事件。浏览器提供的 MutationObserver 是最贴近“HTML相关观察”的原生API,但它只管DOM,不管业务数据。
MutationObserver:监听DOM变动的唯一靠谱选择
想实时知道某个元素被增删、属性被改、文本被替换,MutationObserver 是当前标准且性能可控的方式。它比老式的 DOMNodeInserted 等事件更高效,也避免了轮询开销。
- 必须手动调用
observe()启动监听,不调就不会工作 - 回调函数接收的是
MutationRecord[]数组,不是单个事件对象,需遍历处理 - 默认不递归子节点,要监听深层变动得显式传
{ subtree: true } - 注意内存泄漏:observer 实例长期存在时,若监听目标被移除却没调
disconnect(),可能保留对节点的引用
const target = document.getElementById('log');
const observer = new MutationObserver(records => {
records.forEach(record => {
if (record.type === 'childList') {
console.log('子节点变了', record.addedNodes, record.removedNodes);
}
});
});
observer.observe(target, { childList: true, subtree: true });
自己写简易Observer类:适合监听JS对象状态
如果目标是响应式地更新UI(比如一个 data 对象变,页面某处自动重绘),就得自己封装一个轻量Observer。ES6 Proxy 是目前最直接的实现方式,比 defineProperty 更全面(能监听新增/删除属性)。
- Proxy 的 handler 里,
set拦截赋值,deleteProperty拦截删除,ownKeys可拦截Object.keys - 不要直接在 handler 里触发视图更新——应通知订阅者(callback 或 event),否则耦合太死
- Proxy 无法代理非对象(如原始值、null),也不能监听数组索引赋值(
arr[0] = x),需要用set+Reflect.set组合兜底
function createObservable(obj, onChange) {
return new Proxy(obj, {
set(target, key, value) {
const result = Reflect.set(target, key, value);
onChange({ type: 'set', key, value });
return result;
}
});
}
const state = createObservable({ count: 0 }, ({ key, value }) => {
document.getElementById('count').textContent = value;
});
别把EventTarget当Observer模式来用
EventTarget(包括 Element、document)支持 addEventListener,看起来像发布-订阅,但它本质是事件系统,不是Observer设计模式的实现:它不维护“被观察对象”与“观察者”的绑定关系,也不主动推送状态快照,只是被动分发信号。
- 适合解耦组件通信(如父子组件传消息),不适合替代数据响应式
- 监听自定义事件时,事件名是字符串,无类型检查,容易拼错(
'data-updated'vs'data-upadted') - 忘记
removeEventListener容易导致重复绑定,尤其在SPA组件反复挂载/卸载时
真正需要Observer语义(即“当X变,自动通知所有关心X的人”),还是得靠 MutationObserver 或自己封装的响应式层。DOM和JS对象两条线,得分开理清楚——混着用只会让调试变得模糊。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











