🧩 v-model 与 value 的关系
当你在一个原生 <input> 上使用 v-model 时,Vue 会将其展开为以下代码:
html
预览
xml
1<!-- 你写的代码 -->
2<input v-model="message">
3
4<!-- Vue 展开后的代码 -->
5<input :value="message" @input="message = $event.target.value">
可以看到,v-model 自动利用了 value 属性来展示数据,并监听 input 事件来更新数据。
🆚 Vue 2 与 Vue 3 的核心区别
1. 响应式原理的变革 (根本原因)
这是导致所有行为差异的根源。
- Vue 2 : 使用
Object.defineProperty。它只能劫持对象的已有属性,无法检测到对象属性的动态添加或删除5。 - Vue 3 : 使用
Proxy。它代理整个对象,可以检测到对象属性的任意变化(增、删、改)25。
2. 组件上 v-model 的默认行为
这是你在开发中感受最明显的区别,尤其是在封装自定义组件时。
表格
| 特性 | Vue 2 | Vue 3 |
|---|---|---|
| 默认 Prop | value |
modelValue |
| 默认事件 | input |
update:modelValue |
| 多 Model 支持 | 不支持,需使用 .sync 修饰符 |
原生支持多个 v-model |
代码对比:
-
Vue 2 中的组件使用
html
预览
xml1<!-- 父组件 --> 2<MyComponent v-model="title" /> 3 4<!-- MyComponent 内部 --> 5<template> 6 <!-- 接收 value,触发 input --> 7 <input :value="value" @input="$emit('input', $event.target.value)" /> 8</template> 9<script> 10export default { 11 props: ['value'] // 默认接收 value 12} 13</script> -
Vue 3 中的组件使用
html
预览
xml1<!-- 父组件 --> 2<MyComponent v-model="title" /> 3 4<!-- MyComponent 内部 --> 5<template> 6 <!-- 接收 modelValue,触发 update:modelValue --> 7 <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" /> 8</template> 9<script setup> 10defineProps(['modelValue']) // 默认接收 modelValue 11</script>
3. v-model 修饰符与多绑定
Vue 3 的 v-model 变得更加强大和灵活。
-
多个 v-model :Vue 3 允许你在同一个组件上绑定多个
v-model,通过参数名区分14。html
预览
xml1<!-- Vue 3 语法 --> 2<UserEditor 3 v-model:name="userName" 4 v-model:age="userAge" 5/>这在 Vue 2 中是无法直接实现的,通常需要配合
.sync修饰符来模拟。 -
自定义修饰符:Vue 3 支持更灵活的修饰符扩展2。
4. 在原生元素上的表现
对于原生的 <input>、<textarea>、<select> 等元素,v-model 的用法在 Vue 2 和 Vue 3 中基本一致,都用于简化双向绑定的代码。主要区别体现在自定义组件的封装上。
💡 总结与迁移建议
- 核心变化 :Vue 3 将组件
v-model的默认 prop 从value改为了modelValue,事件从input改为了update:modelValue。 - 迁移注意 :当你将 Vue 2 项目升级到 Vue 3 时,所有自定义表单组件如果依赖默认的
v-model行为,都需要将props中的value改为modelValue,并将$emit('input')改为$emit('update:modelValue')1。 - 兼容写法 :如果你在 Vue 3 中需要兼容旧的组件库(如 Ant Design Vue),它们可能仍然使用
valueprop,这时你需要显式地使用v-model:value来绑定,而不是简写的v-model3。