vue 实现双向绑定
Vue 双向绑定的实现原理
Vue 的双向绑定主要通过 v-model 指令实现,底层基于数据劫持和发布-订阅模式。以下是核心实现机制:
数据劫持(响应式系统)
Vue 使用 Object.defineProperty(Vue 2)或 Proxy(Vue 3)劫持数据对象的属性访问。当数据变化时,触发 setter 通知依赖更新。
// Vue 2 响应式简化实现
function defineReactive(obj, key, val) {
Object.defineProperty(obj, key, {
get() {
return val;
},
set(newVal) {
if (newVal === val) return;
val = newVal;
dep.notify(); // 通知所有订阅者更新
}
});
}
依赖收集(发布-订阅) 每个响应式属性拥有一个 Dep 实例,用于收集依赖(Watcher)。当属性被访问时,当前 Watcher 会被添加到 Dep 中。
class Dep {
constructor() {
this.subs = [];
}
addSub(sub) {
this.subs.push(sub);
}
notify() {
this.subs.forEach(sub => sub.update());
}
}
实现双向绑定的方法
使用 v-model 指令
v-model 是语法糖,自动处理输入事件和值绑定:
<input v-model="message">
<!-- 等价于 -->
<input
:value="message"
@input="message = $event.target.value"
>
自定义组件实现双向绑定
在自定义组件中,需显式定义 value prop 和 input 事件:
<custom-input v-model="msg"></custom-input>
<!-- 组件内部实现 -->
<script>
export default {
props: ['value'],
methods: {
updateValue(newVal) {
this.$emit('input', newVal);
}
}
}
</script>
手动实现数据绑定 通过事件监听和状态更新模拟双向绑定:
<input
:value="text"
@input="text = $event.target.value"
>
<script>
export default {
data() {
return { text: '' }
}
}
</script>
注意事项
- Vue 3 使用
Proxy替代Object.defineProperty,支持深层对象监听和数组变化检测。 - 对于复杂对象,需确保属性初始化时已被 Vue 劫持,或使用
Vue.set/this.$set动态添加响应式属性。 v-model在组件上默认使用modelValueprop 和update:modelValue事件(Vue 3)。






