下面给你整理一份 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>
✅ 解释:
v-model="message"等价于:<input :value="message" @input="message = $event" />ref创建响应式数据
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>
✅ 说明:
- Vue 3 默认使用
modelValue+update:modelValue作为双向绑定的约定 - 子组件通过
$emit('update:modelValue', value)更新父组件
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>
✅ 说明:
v-model:xxx对应子组件的props和$emit('update:xxx')- 可以实现一个组件多个双向绑定
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>
✅ 说明:
localValue保持子组件内部响应式- 使用
$emit通知父组件更新
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️⃣ 总结
- 基础用法:
v-model="state" - 组件内双向绑定:
props.modelValue + $emit('update:modelValue', val) - 命名 v-model:
v-model:xxx对应props.xxx+update:xxx - 修饰符:
.lazy、.number、.trim - TypeScript 类型:
defineProps+defineEmits保证类型安全 - Composition API:可在子组件内部维护本地响应式
ref,通过$emit同步父组件
发表回复