vue 双向绑定 实现原理
Vue 双向绑定的实现原理
Vue 的双向绑定是通过数据劫持结合发布-订阅模式实现的,核心是利用 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)来监听数据变化,并通过事件机制更新视图。
数据劫持
Vue 2.x 使用 Object.defineProperty 对对象的属性进行劫持,通过 getter 和 setter 拦截属性的读取和修改操作。
let data = { message: 'Hello' };
Object.defineProperty(data, 'message', {
get() {
console.log('读取 message');
return this._message;
},
set(newValue) {
console.log('更新 message');
this._message = newValue;
// 触发视图更新
}
});
Vue 3.x 使用 Proxy 代理整个对象,可以监听动态新增的属性,性能更好。
let data = { message: 'Hello' };
let proxy = new Proxy(data, {
get(target, key) {
console.log(`读取 ${key}`);
return target[key];
},
set(target, key, value) {
console.log(`更新 ${key}`);
target[key] = value;
// 触发视图更新
return true;
}
});
发布-订阅模式
Vue 通过 Dep(依赖收集器)和 Watcher(观察者)实现发布-订阅模式。每个响应式属性都有一个 Dep 实例,用于收集依赖的 Watcher。当数据变化时,Dep 会通知所有 Watcher 更新视图。
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
模板编译
Vue 的模板会被编译成渲染函数,渲染函数执行时会触发数据的 getter,从而将当前的 Watcher 添加到依赖列表中。当数据变化时,setter 会触发 Dep 的 notify 方法,通知 Watcher 重新渲染视图。
双向绑定的实现
对于 v-model 指令,Vue 将其转换为 value 属性和 input 事件的语法糖,实现双向绑定。
<input v-model="message" />
// 等价于
<input :value="message" @input="message = $event.target.value" />
总结
Vue 的双向绑定通过以下机制实现:
- 数据劫持:使用
Object.defineProperty或Proxy监听数据变化。 - 依赖收集:通过
Dep和Watcher建立数据和视图的依赖关系。 - 事件监听:通过模板编译和事件绑定实现视图到数据的更新。
这种机制使得数据和视图保持同步,开发者无需手动操作 DOM,提高了开发效率。







