文章目录

Vue3的v-model在组件上的自定义实现

发布于 2026-06-01 02:09:20 · 浏览 16 次 · 评论 0 条

Vue3的v-model在组件上的自定义实现

理解Vue3中v-model的指令如何工作是实现自定义组件双向绑定的基础。本质上,v-model是一个语法糖,它会为组件绑定一个名为 modelValue 的 prop 和一个名为 update:modelValue 的事件。在Vue3中,这一机制得到了增强,允许你在一个组件上使用多个v-model绑定,并且可以自定义每个绑定的名称。


理解组件 v-model 的工作原理

当在父组件中对一个子组件使用 v-model 时:

<ChildComponent v-model="parentData" />

Vue 会在编译时将其转换为:

<ChildComponent
  :modelValue="parentData"
  @update:modelValue="newValue => parentData = newValue"
/>

子组件需要通过 modelValue 这个 prop 来接收父组件的数据,并通过触发 update:modelValue 事件来将新值传回给父组件。


基础实现:自定义单个 v-model

目标:创建一个名为 MyInput 的输入框组件,使其支持 v-model

第一步:定义子组件的 props 和 emits

在子组件的 <script setup> 中,使用 definePropsdefineEmits 宏来声明接收的属性和可以触发的事件。

<!-- MyInput.vue -->
<script setup>
const props = defineProps({
  // 接收父组件通过 v-model 传递的值
  modelValue: {
    type: String,
    required: true
  }
})

const emit = defineEmits([
  // 声明组件可以触发的更新事件
  'update:modelValue'
])
</script>

第二步:在模板中使用 props 并触发事件

在子组件的模板中,将接收到的 modelValue 展示出来,并在输入框的值发生变化时,通过触发 update:modelValue 事件来通知父组件更新数据。

<!-- MyInput.vue -->
<template>
  <input
    type="text"
    :value="props.modelValue"
    @input="$emit('update:modelValue', $event.target.value)"
  />
</template>

第三步:在父组件中使用

父组件现在可以直接对 MyInput 使用 v-model,就像使用原生 HTML 元素一样。

<!-- Parent.vue -->
<template>
  <div>
    <p>父组件中的数据:{{ parentMessage }}</p>
    <MyInput v-model="parentMessage" />
  </div>
</template>

<script setup>
import { ref } from 'vue'
import MyInput from './MyInput.vue'

const parentMessage = ref('Hello')
</script>

进阶实现:多字段绑定 (v-model:参数)

Vue3允许在同一个组件上使用多个 v-model 绑定,通过 v-model:参数名 的语法实现。这极大地增强了组件的灵活性。

目标:创建一个 UserProfileForm 组件,它同时需要用户的“名字”和“邮箱”两个数据。

第一步:定义带有具体名称的 props 和 emits

子组件需要为每个要双向绑定的数据定义一个具体的 prop 名称和对应的更新事件。

<!-- UserProfileForm.vue -->
<script setup>
const props = defineProps({
  // 接收名为 `name` 的绑定
  name: {
    type: String,
    required: true
  },
  // 接收名为 `email` 的绑定
  email: {
    type: String,
    required: true
  }
})

const emit = defineEmits([
  // 声明对应的更新事件
  'update:name',
  'update:email'
])
</script>

第二步:在模板中分别绑定并触发事件

在模板中,为每个表单控件绑定对应的 prop,并在其值变化时触发正确的更新事件。

<!-- UserProfileForm.vue -->
<template>
  <div>
    <label>
      名字:
      <input
        type="text"
        :value="props.name"
        @input="emit('update:name', $event.target.value)"
      />
    </label>
    <br>
    <label>
      邮箱:
      <input
        type="email"
        :value="props.email"
        @input="emit('update:email', $event.target.value)"
      />
    </label>
  </div>
</template>

第三步:在父组件中使用多个 v-model 绑定

父组件使用 v-model:namev-model:email 分别绑定两个不同的响应式数据。

<!-- Parent.vue -->
<template>
  <div>
    <UserProfileForm
      v-model:name="userName"
      v-model:email="userEmail"
    />
    <div>
      <p>父组件显示:</p>
      <p>名字:{{ userName }}</p>
      <p>邮箱:{{ userEmail }}</p>
    </div>
  </div>
</template>

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

const userName = ref('Alice')
const userEmail = ref('alice@example.com')
</script>

使用计算属性优化实现

在上面的实现中,模板里的事件处理略显冗长。我们可以利用 Vue 的计算属性(computed)来使代码更清晰,尤其是在处理复杂的转换逻辑时。

改写子组件

使用 computed 的 getter 和 setter 来封装数据的读取和更新逻辑。

<!-- UserProfileForm.vue (优化版) -->
<script setup>
import { computed } from 'vue'

const props = defineProps({
  name: String,
  email: String
})

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

// 使用计算属性封装 `name` 的双向绑定
const nameValue = computed({
  // getter: 返回父组件传递过来的 prop 值
  get() {
    return props.name
  },
  // setter: 当子组件内部修改此值时,触发事件通知父组件
  set(newValue) {
    emit('update:name', newValue)
  }
})

// 同理封装 `email` 的双向绑定
const emailValue = computed({
  get() {
    return props.email
  },
  set(newValue) {
    emit('update:email', newValue)
  }
})
</script>

模板可以简化为直接绑定这些计算属性。

<!-- UserProfileForm.vue (优化版) -->
<template>
  <div>
    <label>
      名字:
      <input type="text" v-model="nameValue" />
    </label>
    <br>
    <label>
      邮箱:
      <input type="email" v-model="emailValue" />
    </label>
  </div>
</template>

Vue3 与 Vue2 的 v-model API 对比

了解新旧 API 的差异有助于迁移旧代码或理解技术选型。

特性 Vue2 Vue3
默认 Prop value modelValue
默认事件 input update:modelValue
多个绑定 不支持(需用 .sync 修饰符) 支持 (v-model:title, v-model:author)
自定义修饰符 不支持(仅内置 .lazy等) 支持(通过 v-model:capital 并处理 modelModifiers prop)
组件内定义 使用 model 选项 直接使用 propsemits

通过遵循以上步骤,你就可以在Vue3中轻松地为自定义组件实现灵活、强大的 v-model 双向数据绑定了。

评论 (0)

暂无评论,快来抢沙发吧!

扫一扫,手机查看

扫描上方二维码,在手机上查看本文