vue-model实现
Vue 双向数据绑定实现原理
Vue 的双向数据绑定主要通过 v-model 指令实现,其核心是基于数据劫持和发布-订阅模式。
数据劫持
Vue 使用 Object.defineProperty 或 ES6 的 Proxy 来劫持对象的属性,当属性被访问或修改时触发相应的 getter 和 setter。
// 使用 Object.defineProperty 实现数据劫持
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
console.log(`获取 ${key}: ${val}`);
return val;
},
set: function reactiveSetter(newVal) {
console.log(`设置 ${key}: ${newVal}`);
val = newVal;
}
});
}
发布-订阅模式
Vue 通过 Dep 和 Watcher 实现发布-订阅模式,Dep 用于收集依赖,Watcher 用于更新视图。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
class Watcher {
update() {
console.log('视图更新');
}
}
v-model 实现
v-model 本质上是语法糖,结合了 v-bind 和 v-on。以 input 元素为例:
<input v-model="message">
等价于:
<input
:value="message"
@input="message = $event.target.value"
>
自定义组件实现 v-model
在自定义组件中,可以通过 model 选项和 $emit 实现双向绑定。
Vue.component('custom-input', {
props: ['value'],
model: {
prop: 'value',
event: 'input'
},
template: `
<input
:value="value"
@input="$emit('input', $event.target.value)"
>
`
});
使用 Proxy 实现数据劫持
在 Vue 3 中,使用 Proxy 替代 Object.defineProperty,可以更好地处理数组和对象。
function reactive(obj) {
return new Proxy(obj, {
get(target, key) {
console.log(`获取 ${key}`);
return target[key];
},
set(target, key, value) {
console.log(`设置 ${key}`);
target[key] = value;
return true;
}
});
}
总结
Vue 的双向数据绑定通过数据劫持和发布-订阅模式实现,v-model 是其语法糖形式。自定义组件可以通过 model 选项和 $emit 实现类似功能。Vue 3 使用 Proxy 提供了更强大的数据劫持能力。







