下面给你一份 真正到位、从源码原理到最佳实践全覆盖 的
《Vue 中 v-model 的双向绑定实现原理(含 Vue2 / Vue3 最佳实践)》。
这份内容你可以直接用来写技术博客、面试准备、或者项目优化。
🚀 1. v-model 本质是什么?
一句话:
v-model = value + input(Vue2)
v-model = modelValue + update:modelValue(Vue3)
它只是一个 语法糖,把 父组件 → 子组件传值(props) 和
子组件 → 父组件事件回传(emit) 组合在一起,实现双向绑定。
📌 2. Vue2 & Vue3 的 v-model 区别(秒懂对比)
| 框架 | 接收 prop | 触发事件 | 说明 |
|---|---|---|---|
| Vue2 | value | input | 无命名 v-model |
| Vue3 | modelValue | update:modelValue | 支持多 v-model |
⭐ 3. Vue2 v-model 原理(完整讲解 + 代码)
📌 父组件使用
<CustomInput v-model="msg" />
v-model 等价于:
<CustomInput :value="msg" @input="msg = $event" />
📌 子组件(实现双向绑定)
export default {
props: ["value"],
methods: {
onInput(e) {
this.$emit("input", e.target.value);
}
}
}
原理总结(Vue2)
- v-model 自动给子组件传入
value - 子组件改动后发出
input事件 - 父组件监听
input,更新绑定变量
⭐ 4. Vue3 v-model 原理(推荐写法)
📌 父组件使用
<MyInput v-model="msg" />
等价于:
<MyInput :modelValue="msg" @update:modelValue="msg = $event" />
📌 子组件写法(Vue3 最佳实践)
<script setup>
const props = defineProps({
modelValue: String
})
const emit = defineEmits(['update:modelValue'])
function onInput(e) {
emit('update:modelValue', e.target.value)
}
</script>
原理总结(Vue3)
modelValue是固定属性名update:modelValue是固定事件名- 组件中只需要 emit 即可
⭐ 5. Vue3 多 v-model(高级用法 / 面试常问)
<MyPick v-model:title="title" v-model:checked="checked" />
等价于:
<MyPick
:title="title"
@update:title="title = $event"
:checked="checked"
@update:checked="checked = $event"
/>
子组件代码:
defineProps(['title', 'checked'])
defineEmits(['update:title', 'update:checked'])
🔥 6. v-model 的核心实现逻辑(框架底层)
Vue 做的关键事情:
- 生成一个 prop(value/modelValue)
- 生成一个事件(input/update:modelValue)
- 父组件表达式绑定(
msg = $event) - Watcher 监听 + 响应式更新视图
核心思想:
“父传属性 + 子触发事件 = 双向绑定”
🧠 7. 内部原理(深入版,但通俗易懂)
Vue2 :
v-model 编译为:
model: {
value: (msg),
callback: function ($$v) { msg = $$v }
}
在生成 vnode 时:
- 绑定
value属性 - 绑定
input监听 - Watcher 触发 set → notify 更新 DOM
Vue3:
使用 Proxy 的响应式系统:
const state = reactive({ msg: "" })
v-model 绑定的 modelValue 会自动变成 依赖收集的响应式值。
组件 emit 更新 → 外层 state 更新 → 触发 effect → UI 渲染。
🧩 8. v-model 最佳实践(高级开发必看)
✔ 1)组件内部永远不要直接修改 props
错误 ❌:
props.modelValue = xx
正确 ✔:
emit('update:modelValue', newValue)
✔ 2)如果你需要内部状态,使用“受控 + 非受控混合模式”
const innerValue = ref(props.modelValue)
watch(() => props.modelValue, v => innerValue.value = v)
适用于输入框、防抖请求、表单组件等。
✔ 3)自定义事件命名必须遵守 Vue3 标准格式
update:modelValue
update:xxx
否则 v-model 不会生效。
✔ 4)封装表单组件时,永远推荐使用:Vue3 多 v-model
避免用 props.xxx + emit('xxx-update') 这种老模式。
🎯 9. 面试回答模板(30 秒完美回答)
你可以这样背:
在 Vue 中 v-model 是语法糖。
Vue2 通过value+input实现,Vue3 通过modelValue+update:modelValue实现。
本质是父组件向子组件下发 props,子组件通过事件通知父组件更新数据,从而实现双向绑定。
Vue3 支持多个 v-model,同时语义更清晰。
推荐使用 emit(‘update:modelValue’) 这种标准写法。
发表回复