.vue 双向绑定实现原理
Vue 双向绑定实现原理
Vue 的双向绑定核心是通过数据劫持结合发布-订阅模式实现的,主要依赖以下技术:
数据劫持(Object.defineProperty 或 Proxy)
Vue 2.x 使用 Object.defineProperty 对对象的属性进行劫持,通过重写属性的 get 和 set 方法实现监听。Vue 3.x 改用 Proxy 实现更高效的劫持,支持对数组和深层对象的监听。
// Vue 2.x 的简单实现示例
const data = { value: '' };
Object.defineProperty(data, 'value', {
get() {
return this._value;
},
set(newVal) {
this._value = newVal;
console.log('数据更新了'); // 触发更新
}
});
依赖收集与发布-订阅
每个被劫持的属性会关联一个 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 的模板会被编译成渲染函数,解析到 v-model 等指令时:
- 为表单元素绑定
input事件(如text类型输入框)。 - 通过
v-bind将数据绑定到元素的value属性。 - 输入时触发事件更新数据,数据变化后触发重新渲染。
实现双向绑定的关键代码
// 简化的 v-model 实现
function bindInputToData(input, obj, key) {
input.value = obj[key]; // 初始化
input.addEventListener('input', (e) => {
obj[key] = e.target.value; // 数据更新
});
// 假设这里有一个响应式系统监听 obj[key] 的变化
}
Vue 3 的优化
Vue 3 使用 Proxy 替代 Object.defineProperty,解决了以下问题:
- 无需递归遍历对象初始化劫持。
- 直接监听数组变化。
- 支持动态新增属性。
// Vue 3 的 Proxy 实现
const reactive = (obj) => {
return new Proxy(obj, {
get(target, key) {
track(target, key); // 依赖收集
return target[key];
},
set(target, key, value) {
target[key] = value;
trigger(target, key); // 触发更新
return true;
}
});
};
总结
- 数据劫持:通过
Object.defineProperty或Proxy监听数据变化。 - 依赖收集:在
getter中收集依赖,在setter中触发更新。 - 模板编译:将模板中的指令解析为数据绑定和事件监听。
- 更新视图:数据变化时通过虚拟 DOM 高效更新界面。







