Vue3 Options API:如何用v-model关联表单子组件与父组件对象?
问题描述
我按照Vue官方文档的子组件表单v-model参数说明写了代码,目前App.vue通过v-model:first-name和v-model:last-name把父组件的firstLast对象的first、last属性分别绑定到UserName.vue的两个输入框,代码能正常运行。但我想让UserName.vue里用一个包含两个属性的对象来处理,而不是两个单独的变量,该怎么改?
现有代码
App.vue
<script> import UserName from './UserName.vue' export default { components: { UserName }, data() { return { firstLast: { first: 'John', last: 'Doe' } } } } </script> <template> <h1>{{ firstLast.first }} {{ firstLast.last }}</h1> <UserName v-model:first-name="firstLast.first" v-model:last-name="firstLast.last" /> </template>
UserName.vue
<script> export default { props: { firstName: String, lastName: String }, emits: ['update:firstName', 'update:lastName'] } </script> <template> <input type="text" :value="firstName" @input="$emit('update:firstName', $event.target.value)" /> <input type="text" :value="lastName" @input="$emit('update:lastName', $event.target.value)" /> </template>
修改方案
核心是把多个单独的prop合并成一个对象类型的prop,同时调整emit事件和父组件的绑定方式:
1. 修改子组件 UserName.vue
- 替换原有的两个prop为一个
name对象prop,指定类型为Object - 将emits改为
update:name,用于通知父组件更新整个对象 - 输入触发时,通过扩展运算符创建新对象(避免直接修改prop),合并更新后的属性再emit给父组件
修改后的代码:
<script> export default { props: { name: { type: Object, required: true, // 可选:设置默认值 default: () => ({ first: '', last: '' }) } }, emits: ['update:name'] } </script> <template> <input type="text" :value="name.first" @input="$emit('update:name', { ...name, first: $event.target.value })" /> <input type="text" :value="name.last" @input="$emit('update:name', { ...name, last: $event.target.value })" /> </template>
如果需要更严谨的类型校验,可以导入PropType定义对象结构:
import { PropType } from 'vue' // ... props: { name: { type: Object as PropType<{ first: string; last: string }>, required: true } }
2. 修改父组件 App.vue
不再使用多个v-model:参数,直接用单个v-model绑定整个firstLast对象即可:
<script> import UserName from './UserName.vue' export default { components: { UserName }, data() { return { firstLast: { first: 'John', last: 'Doe' } } } } </script> <template> <h1>{{ firstLast.first }} {{ firstLast.last }}</h1> <UserName v-model="firstLast" /> </template>
内容的提问来源于stack exchange,提问作者Tony Moritz
相关产品推荐
相关产品推荐

