vue数据实现双向绑定
Vue 数据双向绑定的实现原理
Vue 的双向绑定主要通过 v-model 指令实现,结合数据劫持(Object.defineProperty 或 Proxy)和发布-订阅模式。以下是核心实现逻辑:
数据劫持
Vue 2.x 使用 Object.defineProperty 监听对象属性的变化,Vue 3.x 改用 Proxy 实现更高效的响应式系统。
Vue 2.x 示例:
function observe(data) {
if (!data || typeof data !== 'object') return;
Object.keys(data).forEach(key => {
let value = data[key];
const dep = new Dep(); // 依赖收集器
observe(value); // 递归监听嵌套属性
Object.defineProperty(data, key, {
get() {
Dep.target && dep.addSub(Dep.target); // 收集依赖
return value;
},
set(newVal) {
if (newVal === value) return;
value = newVal;
observe(newVal); // 新值如果是对象,继续监听
dep.notify(); // 通知更新
}
});
});
}
Vue 3.x 示例(Proxy):

function reactive(data) {
if (typeof data !== 'object' || data === null) return data;
const observed = new Proxy(data, {
get(target, key) {
track(target, key); // 依赖追踪
return Reflect.get(target, key);
},
set(target, key, value) {
Reflect.set(target, key, value);
trigger(target, key); // 触发更新
return true;
}
});
return observed;
}
依赖收集与派发更新
通过 Dep 类和 Watcher 类实现依赖管理:
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
constructor(vm, key, cb) {
this.vm = vm;
this.key = key;
this.cb = cb;
Dep.target = this;
this.value = vm[key]; // 触发 getter 收集依赖
Dep.target = null;
}
update() {
const newValue = this.vm[this.key];
if (newValue !== this.value) {
this.cb(newValue);
}
}
}
v-model 的实现
v-model 本质是语法糖,结合 :value 和 @input:
<input v-model="message">
<!-- 等价于 -->
<input :value="message" @input="message = $event.target.value">
对于自定义组件,需通过 model 选项显式声明:

Vue.component('custom-input', {
props: ['value'],
model: {
prop: 'value',
event: 'change'
},
template: `
<input
:value="value"
@input="$emit('change', $event.target.value)"
>
`
});
实现双向绑定的注意事项
-
数组和对象的监听限制
Vue 2.x 中直接通过索引修改数组或增删对象属性不会触发更新,需使用Vue.set或数组的变异方法(如push)。 -
性能优化
避免深层嵌套数据结构,大对象使用Object.freeze()跳过响应式处理。 -
Vue 3 的改进
Proxy 支持原生监听数组变化和动态属性添加,无需特殊 API。


