vue双向绑定实现逻辑
Vue 双向绑定的实现逻辑
Vue 的双向绑定核心是通过数据劫持结合发布-订阅模式实现的,主要依赖 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)来监听数据变化。
核心实现步骤
数据劫持(Data Observer)
通过 Object.defineProperty 或 Proxy 拦截对象的属性访问和修改。当数据被读取时,触发 getter 并收集依赖;当数据被修改时,触发 setter 并通知依赖更新。
// Vue 2.x 使用 Object.defineProperty
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`读取 ${key}`);
return val;
},
set(newVal) {
if (newVal !== val) {
console.log(`更新 ${key}`);
val = newVal;
}
}
});
}
依赖收集(Dependency Tracking) 每个响应式数据维护一个依赖列表(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());
}
}
Watcher(订阅者) Watcher 是数据和视图之间的桥梁。当模板或计算属性中读取数据时,会创建一个 Watcher 并订阅数据的变化。数据变化时,Watcher 触发回调更新视图。
let target = null;
function watcher(fn) {
target = fn;
fn();
target = null;
}
双向绑定的实现
v-model 的实现
v-model 是语法糖,本质上是 :value 和 @input 的组合。例如对于 <input v-model="message">,实际转换为:
<input
:value="message"
@input="message = $event.target.value"
>
Vue 3.x 的改进
Vue 3.x 使用 Proxy 替代 Object.defineProperty,解决了无法监听新增属性和数组变化的问题:
// Vue 3.x 使用 Proxy
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
track(target, key);
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key);
}
});
}
总结
- 数据劫持:通过
Object.defineProperty或Proxy监听数据变化。 - 依赖收集:在数据读取时收集依赖(Watcher),存储到 Dep 中。
- 派发更新:数据变化时通知 Dep,触发所有 Watcher 更新视图。
- v-model:通过
:value绑定数据和@input监听输入事件实现双向绑定。







