08Vue3 表单输入绑定详解
Vue3 提供了 v-model 指令来实现表单元素和数据的双向绑定,使表单处理更加简单高效。
一、基本概念
1.1 v-model 的核心作用
-
将表单输入元素与 Vue 实例的数据进行双向绑定
-
自动监听用户的输入事件并更新数据
-
数据变化时自动更新表单显示
1.2 v-model 与 v-bind + v-on 的关系
在 Vue3 中,v-model 实际上是语法糖:
<!-- v-model 写法 --> <input v-model="message"> <!-- 等价于 --> <input :value="message" @input="message = $event.target.value" >
二、各种表单元素的使用方法
2.1 文本输入框 (Text Input)
<template>
<div>
<input v-model="text" placeholder="请输入文本">
<p>输入的内容:{{ text }}</p>
<!-- 修饰符 -->
<input v-model.lazy="text" placeholder="懒更新">
<input v-model.trim="text" placeholder="自动去除首尾空格">
<input v-model.number="number" placeholder="转为数字" type="number">
</div>
</template>
<script setup>
import { ref } from 'vue'
const text = ref('')
const number = ref(0)
</script>
2.2 多行文本 (Textarea)
<template>
<div>
<textarea v-model="message" rows="3"></textarea>
<p>消息内容:{{ message }}</p>
<!-- 插值语法在 textarea 中无效 -->
<!-- 错误写法:<textarea>{{ message }}</textarea> -->
</div>
</template>
<script setup>
import { ref } from 'vue'
const message = ref('')
</script>
2.3 复选框 (Checkbox)
单个复选框:
<template>
<div>
<input type="checkbox" id="agree" v-model="isAgreed">
<label for="agree">我同意协议</label>
<p>状态:{{ isAgreed }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isAgreed = ref(false)
</script>
多个复选框(绑定到数组):
<template>
<div>
<input type="checkbox" id="vue" value="Vue" v-model="checkedNames">
<label for="vue">Vue</label>
<input type="checkbox" id="react" value="React" v-model="checkedNames">
<label for="react">React</label>
<input type="checkbox" id="angular" value="Angular" v-model="checkedNames">
<label for="angular">Angular</label>
<p>选中的框架:{{ checkedNames }}</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const checkedNames = ref([])
</script>
三、修饰符 (Modifiers)
3.1 .lazy - 懒更新
<template>
<input v-model.lazy="message">
<!-- 在 change 事件而非 input 事件后更新 -->
</template>
3.2 .number - 自动转为数字
<template>
<input v-model.number="age" type="number">
<!-- 将输入值自动转为数字类型 -->
</template>
3.3 .trim - 自动去除首尾空格
<template> <input v-model.trim="username"> <!-- 自动去除输入内容的首尾空格 --> </template>
四、进阶用法
4.1 自定义组件的 v-model
Vue3 中,组件可以使用多个 v-model:
子组件 ChildComponent.vue:
子组件 ChildComponent.vue: vue <template> <input :value="modelValue" @input="$emit('update:modelValue', $event.target.value)" > <input :value="title" @input="$emit('update:title', $event.target.value)" > </template> <script setup> defineProps(['modelValue', 'title']) defineEmits(['update:modelValue', 'update:title']) </script>
父组件中使用: vue <template> <ChildComponent v-model="message" v-model:title="pageTitle" /> </template> <script setup> import { ref } from 'vue' import ChildComponent from './ChildComponent.vue' const message = ref('') const pageTitle = ref('') </script>
4.2 计算属性与表单绑定
<template>
<div>
<input v-model="fullName">
<p>名字:{{ firstName }}</p>
<p>姓氏:{{ lastName }}</p>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const firstName = ref('张')
const lastName = ref('三')
const fullName = computed({
get() {
return `${firstName.value} ${lastName.value}`
},
set(newValue) {
const [first, last] = newValue.split(' ')
firstName.value = first || ''
lastName.value = last || ''
}
})
</script>
4.3 表单验证示例
<template>
<form @submit.prevent="handleSubmit">
<div>
<input
v-model.trim="form.email"
type="email"
placeholder="邮箱"
:class="{ 'error': errors.email }"
>
<span v-if="errors.email" class="error-text">{{ errors.email }}</span>
</div>
<div>
<input
v-model="form.password"
type="password"
placeholder="密码"
:class="{ 'error': errors.password }"
>
<span v-if="errors.password" class="error-text">{{ errors.password }}</span>
</div>
<button type="submit" :disabled="isSubmitting">提交</button>
</form>
</template>
<script setup>
import { ref, reactive } from 'vue'
const form = reactive({
email: '',
password: ''
})
const errors = reactive({
email: '',
password: ''
})
const isSubmitting = ref(false)
const validateForm = () => {
let isValid = true
// 验证邮箱
if (!form.email) {
errors.email = '邮箱不能为空'
isValid = false
} else if (!/^\S+@\S+\.\S+$/.test(form.email)) {
errors.email = '邮箱格式不正确'
isValid = false
} else {
errors.email = ''
}
// 验证密码
if (!form.password) {
errors.password = '密码不能为空'
isValid = false
} else if (form.password.length < 6) {
errors.password = '密码至少6位'
isValid = false
} else {
errors.password = ''
}
return isValid
}
const handleSubmit = async () => {
if (!validateForm()) return
isSubmitting.value = true
try {
// 提交表单逻辑
console.log('提交表单:', form)
} finally {
isSubmitting.value = false
}
}
</script>
<style scoped>
.error {
border-color: red;
}
.error-text {
color: red;
font-size: 12px;
}
</style>
五、最佳实践
-
使用
.trim和.number修饰符处理常见的数据清洗需求 -
复杂的表单验证推荐使用专门的验证库(如 VeeValidate、yup)
-
大型表单考虑使用 Composition API 抽离表单逻辑
-
性能优化:对不需要实时更新的输入使用
.lazy修饰符 -
可访问性:始终为表单元素添加合适的
label
六、与 Vue2 的区别
-
多个
v-model支持:Vue3 支持在单个组件上使用多个v-model -
自定义修饰符:Vue3 允许自定义
v-model修饰符 -
modelValue默认属性名:替代 Vue2 的value -
update:modelValue默认事件名:替代 Vue2 的input
Vue3 的表单绑定保持了简洁的语法,同时提供了更强大的功能和更好的 TypeScript 支持。

浙公网安备 33010602011771号