Vue 3 组件 v-model 多个绑定

FreeGuideOnline 最新 2026-07-06

<ChildComponent :modelValue="parentData" @update:modelValue="parentData = $event" />


因此,子组件的 props 需要接收 `modelValue`,并在变更时触发 `update:modelValue` 事件。这是单一绑定的基础。

### 引入命名 v-model:实现多个绑定

Vue 3 的 v-model 支持参数传递,语法为 `v-model:xxx`,其中 `xxx` 是你自定义的名称。例如:

```html
<UserProfileForm
  v-model:username="user.name"
  v-model:email="user.email"
/>

上面的写法等价于:

<UserProfileForm
  :username="user.name"
  @update:username="user.name = $event"
  :email="user.email"
  @update:email="user.email = $event"
/>

子组件如何接收多个 v-model

子组件需要为每个 v-model 声明对应的 propemit 事件。事件名采用 update:propName 的格式。

假设我们构建一个自定义输入组件 UserProfileForm,它同时管理用户名和邮箱。

子组件 (UserProfileForm.vue)

<template>
  <div>
    <label>
      用户名:
      <input
        :value="username"
        @input="$emit('update:username', $event.target.value)"
      />
    </label>
    <label>
      邮箱:
      <input
        :value="email"
        @input="$emit('update:email', $event.target.value)"
      />
    </label>
  </div>
</template>

<script setup>
defineProps({
  username: String,
  email: String
})

defineEmits(['update:username', 'update:email'])
</script>

父组件使用

<template>
  <UserProfileForm
    v-model:username="user.name"
    v-model:email="user.email"
  />
</template>

<script setup>
import { reactive } from 'vue'
import UserProfileForm from './UserProfileForm.vue'

const user = reactive({
  name: '张三',
  email: 'zhangsan@example.com'
})
</script>

这样,user.nameuser.email 便实现了双向绑定,子组件内的输入变化会实时同步回父组件状态。

处理 v-model 修饰符

Vue 3 同样支持自定义 v-model 修饰符。当使用多个 v-model 时,修饰符可以通过 prop modelModifiersxxxModifiers 传递(其中 xxx 是你的命名)。

例如,我们希望 username 的输入自动将首字母大写。

父组件添加 .capitalize 修饰符(该修饰符为自定义):

<UserProfileForm
  v-model:username.capitalize="user.name"
  v-model:email="user.email"
/>

子组件需要声明对应的 modifiers prop,并根据修饰符调整行为:

<script setup>
const props = defineProps({
  username: String,
  email: String,
  usernameModifiers: { default: () => ({}) }
})

const emit = defineEmits(['update:username', 'update:email'])

function updateUsername(event) {
  let value = event.target.value
  if (props.usernameModifiers.capitalize) {
    value = value.charAt(0).toUpperCase() + value.slice(1)
  }
  emit('update:username', value)
}
</script>

<template>
  <div>
    <label>
      用户名:
      <input :value="username" @input="updateUsername" />
    </label>
    <!-- 邮箱部分保持不变 -->
  </div>
</template>

如果使用默认的 v-model(无命名),修饰符会通过 modelModifiers prop 传入。

使用可组合函数简化多个 v-model

当组件包含多个 v-model 时,可以为每个绑定创建一个可复用的逻辑。例如封装一个 useModel 辅助函数:

import { computed } from 'vue'

export function useModel(props, name, emit) {
  const event = `update:${name}`
  return computed({
    get: () => props[name],
    set: (value) => emit(event, value)
  })
}

然后在子组件中使用:

<script setup>
import { useModel } from './useModel'

const props = defineProps(['username', 'email'])
const emit = defineEmits(['update:username', 'update:email'])

const username = useModel(props, 'username', emit)
const email = useModel(props, 'email', emit)
</script>

<template>
  <input v-model="username" />
  <input v-model="email" />
</template>