vue双向绑定如何实现
Vue 双向绑定的实现原理
Vue 的双向绑定是通过数据劫持结合发布者-订阅者模式实现的,核心是 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)。
Vue 2.x 的实现方式
数据劫持
使用 Object.defineProperty 劫持对象的属性,在属性被访问或修改时触发 getter 和 setter。
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get() {
console.log('get value:', val);
return val;
},
set(newVal) {
console.log('set value:', newVal);
val = newVal;
}
});
}
依赖收集
在 getter 中收集依赖(Watcher),在 setter 中通知依赖更新。
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
Watcher
Watcher 是观察者,负责更新视图。
function watcher(fn) {
target = fn;
fn();
target = null;
}
Vue 3.x 的实现方式
Proxy 替代 Object.defineProperty
Vue 3.x 使用 Proxy 实现数据劫持,可以监听对象和数组的变化,无需递归遍历对象。
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log('get value:', target[key]);
return target[key];
},
set(target, key, value) {
console.log('set value:', value);
target[key] = value;
return true;
}
});
}
Reflect 配合 Proxy
使用 Reflect 操作对象,避免直接操作原对象。
function reactive(obj) {
return new Proxy(obj, {
get(target, key, receiver) {
const res = Reflect.get(target, key, receiver);
track(target, key); // 依赖收集
return res;
},
set(target, key, value, receiver) {
const res = Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return res;
}
});
}
双向绑定的具体应用
v-model 的实现v-model 是语法糖,本质上是 :value 和 @input 的结合。
<input v-model="message" />
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value" />
自定义组件的双向绑定
通过 model 选项和 $emit 实现自定义组件的双向绑定。
Vue.component('custom-input', {
props: ['value'],
model: {
prop: 'value',
event: 'input'
},
template: `
<input
:value="value"
@input="$emit('input', $event.target.value)"
/>
`
});
总结
Vue 的双向绑定通过数据劫持和发布-订阅模式实现,Vue 2.x 使用 Object.defineProperty,Vue 3.x 使用 Proxy。v-model 是语法糖,简化了表单输入和组件通信的双向绑定逻辑。







