vue双向绑定实现方式
Vue 双向绑定的实现方式
Vue 的双向绑定主要通过 v-model 指令实现,结合数据劫持和发布-订阅模式完成数据与视图的同步更新。以下是核心实现原理及方式:
数据劫持(响应式原理)
Vue 使用 Object.defineProperty(Vue 2.x)或 Proxy(Vue 3.x)劫持数据的访问和修改,触发依赖收集和更新。
Vue 2.x 实现示例:
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
console.log(`读取 ${key}: ${val}`);
return val;
},
set(newVal) {
if (newVal !== val) {
console.log(`设置 ${key}: ${newVal}`);
val = newVal;
// 触发视图更新
}
}
});
}
Vue 3.x 使用 Proxy:
const reactive = (target) => {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return true;
}
});
};
发布-订阅模式
通过 Dep(依赖收集器)和 Watcher(观察者)实现数据变化时的通知机制:
- Dep:每个响应式属性对应一个 Dep 实例,用于管理所有依赖(Watcher)。
- Watcher:在模板编译时创建,订阅数据变化并触发更新。
class Dep {
constructor() {
this.subscribers = [];
}
depend() {
if (target && !this.subscribers.includes(target)) {
this.subscribers.push(target);
}
}
notify() {
this.subscribers.forEach(sub => sub());
}
}
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)"
>
`
});
双向绑定的注意事项
- 性能影响:深层对象或数组的劫持可能带来性能开销,必要时使用
Object.freeze优化。 - 局限性:Vue 2.x 无法检测到对象属性的添加或删除,需使用
Vue.set或Vue.delete。 - 替代方案:复杂场景可手动拆分
:value和@change实现更灵活的控制。
通过以上机制,Vue 实现了高效的双向数据绑定,简化了表单和组件间的数据流管理。







