在 Vue.js 3.5 中,表单控件绑定是实现用户输入与数据模型同步的核心机制,主要通过 v-model 指令完成。该指令本质上是语法糖,会根据控件类型自动绑定不同的属性和事件,例如文本输入框绑定 value 属性和 input 事件,复选框绑定 checked 属性和 change 事件等 [13]。以下以“用户注册表单”为案例,分类展示不同控件的绑定方式及数据类型特性。
文本框(input/textarea)
文本类控件(单行输入框、多行文本框)通过 v-model 绑定字符串类型数据。例如用户名输入框:
<template>
<div class="form-group">
<label>用户名:</label>
<input type="text" v-model="username" placeholder="请输入用户名" />
</div>
<div class="form-group">
<label>个人简介:</label>
<textarea v-model="bio" placeholder="请输入个人简介"></textarea>
</div>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('') // 字符串类型
const bio = ref('') // 字符串类型
</script>
单选框(radio)
单选框组通过相同的 v-model 绑定,value 为具体选项值,绑定数据为字符串类型(选中项的 value):
<template>
<div class="form-group">
<label>性别:</label>
<input type="radio" v-model="gender" value="male" id="male" />
<label for="male">男</label>
<input type="radio" v-model="gender" value="female" id="female" />
<label for="female">女</label>
</div>
</template>
<script setup>
import { ref } from 'vue'
const gender = ref('male') // 字符串类型,默认选中"男"
</script>
多选框(checkbox)
checked 状态) v-model 绑定数组,value 为选项值,数组元素为选中项的 value<template>
<div class="form-group">
<label>
<input type="checkbox" v-model="agree" /> 同意用户协议
</label>
</div>
<div class="form-group">
<label>爱好:</label>
<input type="checkbox" v-model="hobbies" value="reading" id="reading" />
<label for="reading">阅读</label>
<input type="checkbox" v-model="hobbies" value="sports" id="sports" />
<label for="sports">运动</label>
<input type="checkbox" v-model="hobbies" value="coding" id="coding" />
<label for="coding">编程</label>
</div>
</template>
<script setup>
import { ref } from 'vue'
const agree = ref(false) // 布尔值
const hobbies = ref([]) // 数组类型,存储选中的爱好
</script>
下拉框(select)
v-model 绑定字符串,option 的 value 为选项值 multiple 属性,v-model 绑定数组<template>
<div class="form-group">
<label>城市:</label>
<select v-model="city">
<option value="">请选择</option>
<option value="beijing">北京</option>
<option value="shanghai">上海</option>
<option value="guangzhou">广州</option>
</select>
</div>
<div class="form-group">
<label>技能(可多选):</label>
<select v-model="skills" multiple>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
</select>
</div>
</template>
<script setup>
import { ref } from 'vue'
const city = ref('') // 字符串类型
const skills = ref([]) // 数组类型(multiple时)
</script>
绑定值类型总结:
表单验证是确保用户输入合法性的关键环节,Vue.js 支持多种验证策略,以下结合“用户注册表单”需求,对比三种实现方案。
1. HTML5 原生验证
利用 HTML5 表单属性(如 required、minlength、pattern)进行基础验证,结合 invalid 事件监听错误:
<template>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<label>用户名:</label>
<input
type="text"
v-model="username"
required
minlength="3"
@invalid="handleInvalid($event, 'username')"
placeholder="至少3个字符"
/>
<span class="error-msg">{{ errorMsg.username }}</span>
</div>
<div class="form-group">
<label>手机号:</label>
<input
type="tel"
v-model="phone"
pattern="^1[3-9]\d{9}$"
@invalid="handleInvalid($event, 'phone')"
placeholder="请输入手机号"
/>
<span class="error-msg">{{ errorMsg.phone }}</span>
</div>
<button type="submit">注册</button>
</form>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const phone = ref('')
const errorMsg = ref({})
const handleInvalid = (e, field) => {
e.preventDefault() // 阻止浏览器默认错误提示
switch(field) {
case 'username':
errorMsg.value.username = e.target.validity.valueMissing
? '用户名必填'
: '用户名至少3个字符'
break
case 'phone':
errorMsg.value.phone = '请输入合法手机号'
break
}
}
const handleSubmit = () => {
// 触发表单整体验证
const isValid = document.querySelector('form').checkValidity()
if (isValid) alert('注册成功!')
}
</script>
2. 自定义验证函数
通过编写 validateForm 函数实现复杂逻辑验证,结合 errorMsg 显示自定义错误信息:
<template>
<form @submit.prevent="handleSubmit">
<div class="form-group">
<label>用户名:</label>
<input
type="text"
v-model="username"
@input="validateField('username')"
placeholder="请输入用户名"
/>
<span class="error-msg">{{ errorMsg.username }}</span>
</div>
<div class="form-group">
<label>密码:</label>
<input
type="password"
v-model="password"
@input="validateField('password')"
placeholder="至少6个字符"
/>
<span class="error-msg">{{ errorMsg.password }}</span>
</div>
<button type="submit">注册</button>
</form>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const password = ref('')
const errorMsg = ref({})
// 单个字段验证
const validateField = (field) => {
switch(field) {
case 'username':
errorMsg.value.username = username.value ? '' : '用户名不能为空'
break
case 'password':
errorMsg.value.password = password.value.length >=6 ? '' : '密码至少6个字符'
break
}
}
// 整体表单验证
const validateForm = () => {
validateField('username')
validateField('password')
return Object.values(errorMsg.value).every(msg => !msg)
}
const handleSubmit = () => {
if (validateForm()) {
alert('注册成功!')
}
}
</script>
3. VeeValidate 声明式验证
引入 VeeValidate 库(Vue 3 推荐使用 v4+ 版本),通过 useForm 和 defineField 实现声明式验证规则:
<template>
<form @submit.prevent="handleSubmit(onSubmit)">
<div class="form-group">
<label>用户名:</label>
<input type="text" v-model="username" />
<span class="error-msg">{{ errors.username }}</span>
</div>
<div class="form-group">
<label>密码:</label>
<input type="password" v-model="password" />
<span class="error-msg">{{ errors.password }}</span>
</div>
<button type="submit">注册</button>
</form>
</template>
<script setup>
import { useForm, defineField } from 'vee-validate'
import { required, minLength } from '@vee-validate/rules'
// 定义验证规则
const { handleSubmit, errors } = useForm({
initialValues: { username: '', password: '' },
validationSchema: {
username: defineField('username', required('用户名必填')),
password: defineField('password', minLength(6, '密码至少6个字符'))
}
})
// 提交处理
const onSubmit = (values) => {
alert('注册成功!', values)
}
</script>
验证触发方式:
@input 事件或 VeeValidate 的 validateOnInput: true(默认) handleSubmit 中触发整体验证 errorMsg 对象或 VeeValidate 的 errors 对象绑定到 DOM,实现错误信息动态显示在实际开发中,经常需要封装通用表单组件(如带标签、验证、错误提示的输入框)。以下以 MyInput 组件为例,说明如何实现支持 v-model 双向绑定及自定义验证的表单组件。
1. 组件原理
Vue 中组件的 v-model 本质是 props: modelValue 与 emit: update:modelValue 的语法糖,即:<MyInput v-model="username" /> 等价于 <MyInput :modelValue="username" @update:modelValue="username = $event" />
2. MyInput 组件实现
封装支持 label、placeholder、自定义验证的输入框组件:
<!-- MyInput.vue -->
<template>
<div class="my-input">
<label v-if="label" class="input-label">{{ label }}</label>
<input
type="text"
:placeholder="placeholder"
:value="modelValue"
@input="$emit('update:modelValue', $event.target.value)"
@blur="validate"
/>
<span class="error-msg" v-if="errorMsg">{{ errorMsg }}</span>
</div>
</template>
<script setup>
import { ref, defineProps, defineEmits } from 'vue'
// 定义 props
const props = defineProps({
modelValue: { type: String, required: true },
label: { type: String, default: '' },
placeholder: { type: String, default: '' },
// 自定义验证函数(可选)
validator: { type: Function, default: () => true }
})
// 定义 emits
const emit = defineEmits(['update:modelValue'])
// 错误信息
const errorMsg = ref('')
// 验证逻辑
const validate = () => {
const result = props.validator(props.modelValue)
errorMsg.value = typeof result === 'string' ? result : ''
}
</script>
<style scoped>
.my-input { margin-bottom: 16px; }
.input-label { display: inline-block; width: 80px; }
input { padding: 8px; width: 200px; }
.error-msg { color: red; font-size: 12px; margin-left: 84px; }
</style>
3. 父组件使用方式
在“用户注册表单”中使用 MyInput,并传入自定义验证(如手机号格式):
<!-- RegisterForm.vue -->
<template>
<form @submit.prevent="handleSubmit">
<MyInput
v-model="username"
label="用户名"
placeholder="请输入用户名"
:validator="validateUsername"
/>
<MyInput
v-model="phone"
label="手机号"
placeholder="请输入手机号"
:validator="validatePhone"
/>
<button type="submit">注册</button>
</form>
</template>
<script setup>
import { ref } from 'vue'
import MyInput from './MyInput.vue'
const username = ref('')
const phone = ref('')
// 用户名验证:非空
const validateUsername = (value) => {
if (!value) return '用户名不能为空'
return true
}
// 手机号验证:格式校验
const validatePhone = (value) => {
if (!value) return '手机号不能为空'
const reg = /^1[3-9]\d{9}$/
if (!reg.test(value)) return '手机号格式错误'
return true
}
const handleSubmit = () => {
// 触发所有子组件验证(实际项目可通过 refs 实现)
alert('注册成功!', { username: username.value, phone: phone.value })
}
</script>
3. 组件参数说明
| Props | 类型 | 说明 | 默认值 |
|---|---|---|---|
| modelValue | String | 绑定值(v-model) | - |
| label | String | 标签文本 | - |
| placeholder | String | 输入框提示文本 | '请输入' |
| validator | Function | 自定义验证函数 | () => true |
自定义验证函数规则:
value) true(验证通过)或错误信息字符串(验证失败) @blur 事件在输入框失焦时触发通过以上实现,MyInput 组件既支持 v-model 双向绑定,又能灵活接入自定义验证逻辑,可复用於各类表单场景。
表单处理是 Vue.js 开发中的核心场景,主要涉及三方面:
v-model 根据控件类型绑定不同数据类型(字符串/布尔/数组) modelValue + update:modelValue 实现 v-model,结合 props 与 emit 实现复用与扩展掌握这些技巧可有效提升表单开发效率,满足从简单到复杂场景的需求。