深入理解 Vue3 的 v-model
Vue3 对 v-model 做了非常重要的改进。
相较于 Vue2 的单一绑定机制,Vue3 的 v-model 不仅可以在组件中使用,还可以指定多个 props 来实现更灵活的数据双向绑定。
一、基础原理
v-model 是语法糖,本质上是:
- 一个 props 绑定(数据输入)
- 一个事件监听(数据输出)
在原生标签上,Vue 会自动解析为 value + input事件 的组合。
<input v-model="data" />
等价于:
<input
:value="data"
@input="data = $event.target.value"
/>
二、在组件上的 v-model
当我们在组件上使用时:
<Children v-model="data" />
Vue3 会被编译为:
<Children
:modelValue="data"
@update:modelValue="data = $event"
/>
这里的两点非常重要:
| 元素类型 | $event 的含义 |
|---|---|
| 原生 DOM | 原生事件对象,例如 input 事件的 event |
| 自定义组件 | 子组件 emit() 传出的参数(不是事件对象) |
所以:
- 在
<input>上要写data = $event.target.value - 在
<Children>上直接写data = $event
三、子组件中的写法
在子组件中(假设使用 <script setup> 语法):
<script setup lang="ts">
const props = defineProps<{
modelValue: string
}>()
const emit = defineEmits<{
(e: 'update:modelValue', value: string): void
}>()
// 例如在子组件内部某个输入事件中:
function changeValue(e: Event) {
emit('update:modelValue', (e.target as HTMLInputElement).value)
}
</script>
这样父组件绑定的 v-model="data" 就会自动接收子组件 emit 传回来的值,实现双向绑定。
四、命名多个 v-model
Vue3 支持一个组件定义多个 v-model:
<Children
v-model:age="age"
v-model:name="name"
/>
它会被编译为:
<Children
:age="age"
@update:age="age = $event"
:name="name"
@update:name="name = $event"
/>
此时子组件中应当定义相应的 props 和 emits:
<script setup lang="ts">
const props = defineProps<{
age: number
name: string
}>()
const emit = defineEmits<{
(e: 'update:age', value: number): void
(e: 'update:name', value: string): void
}>()
</script>
五、总结
| Vue2 写法 | Vue3 写法 | 差异 |
|---|---|---|
value + input | modelValue + update:modelValue | 属性名不同 |
只能一个 v-model | 可定义多个命名 v-model | 灵活性提升 |
$event.target.value | $event 即 emit 传值 | 组件事件不再是原生事件对象 |
小结记忆口诀
v-model= 绑定一个prop+ 监听一个update:prop事件。原生用
target.value,组件用$event。多个数据双向绑定?就用命名的
v-model:xxx。# v-model 在vue3 中 v-model 相较于 vue2 有了扩展