菜鸟-创作你的创作

Vue3中v-model实现双向数据绑定的全面指南

下面给你整理一份 Vue 3 中 v-model 双向数据绑定的全面指南,覆盖基础用法、命名 v-model、组件自定义绑定、修饰符以及进阶技巧,附带完整示例。


1️⃣ 基础用法

在 Vue 3 中,v-model 用于实现父组件和子组件之间的 双向绑定

<template>
  <div>
    <input v-model="message" placeholder="请输入内容" />
    <p>你输入的内容:{{ message }}</p>
  </div>
</template>

<script setup lang="ts">
import { ref } from 'vue'

const message = ref('')
</script>

✅ 解释:


2️⃣ 组件内使用 v-model

2.1 父组件

<MyInput v-model="username" />
<p>用户名:{{ username }}</p>

2.2 子组件实现

<template>
  <input :value="modelValue" @input="$emit('update:modelValue', $event)" />
</template>

<script setup lang="ts">
import { defineProps } from 'vue'

const props = defineProps<{ modelValue: string }>()
</script>

✅ 说明:


3️⃣ 多个 v-model(命名 v-model)

Vue 3 支持 一个组件多个 v-model

父组件:

<MyInput v-model:title="title" v-model:content="content" />

子组件:

<template>
  <input
    :value="title"
    @input="$emit('update:title', $event)"
    placeholder="标题"
  />
  <textarea
    :value="content"
    @input="$emit('update:content', $event)"
    placeholder="内容"
  ></textarea>
</template>

<script setup lang="ts">
import { defineProps } from 'vue'

const props = defineProps<{
  title: string
  content: string
}>()
</script>

✅ 说明:


4️⃣ v-model 修饰符

修饰符用途
.lazy绑定值在 change 事件触发时更新
.number自动将输入值转为数字
.trim自动去掉首尾空格

示例:

<input v-model.number="age" placeholder="请输入年龄" />
<input v-model.trim="username" placeholder="请输入用户名" />
<input v-model.lazy="email" placeholder="请输入邮箱" />


5️⃣ 自定义组件内实现修饰符

如果子组件也想支持修饰符,需要在 $emit 时处理:

<script setup lang="ts">
import { defineProps, toRef } from 'vue'

const props = defineProps<{ modelValue: string }>()
const value = toRef(props, 'modelValue')

// 自定义处理 trim
const onInput = (e: Event) => {
  const input = e.target as HTMLInputElement
  const val = input.value.trim()
  value.value = val
  emit('update:modelValue', val)
}
</script>


6️⃣ 结合 Composition API 使用 v-model

<script setup lang="ts">
import { ref, defineProps, defineEmits } from 'vue'

const props = defineProps<{ modelValue: string }>()
const emit = defineEmits(['update:modelValue'])

const localValue = ref(props.modelValue)

const updateValue = (val: string) => {
  localValue.value = val
  emit('update:modelValue', val)
}
</script>

<template>
  <input :value="localValue" @input="updateValue($event.target.value)" />
</template>

✅ 说明:


7️⃣ v-model 与 TypeScript 类型安全

const props = defineProps<{ modelValue: string | number }>()
const emit = defineEmits<(e: 'update:modelValue', value: string | number) => void>()

✅ 优势:


8️⃣ 进阶示例:表单组件

<template>
  <form @submit.prevent="submitForm">
    <input v-model.trim="form.username" placeholder="用户名" />
    <input v-model.number="form.age" placeholder="年龄" type="number" />
    <button type="submit">提交</button>
  </form>
</template>

<script setup lang="ts">
import { reactive } from 'vue'

const form = reactive({
  username: '',
  age: 0
})

const submitForm = () => {
  console.log('提交表单:', form)
}
</script>


9️⃣ 总结

  1. 基础用法v-model="state"
  2. 组件内双向绑定props.modelValue + $emit('update:modelValue', val)
  3. 命名 v-modelv-model:xxx 对应 props.xxx + update:xxx
  4. 修饰符.lazy.number.trim
  5. TypeScript 类型defineProps + defineEmits 保证类型安全
  6. Composition API:可在子组件内部维护本地响应式 ref,通过 $emit 同步父组件
退出移动版