Vue 3 入门教程 9 - 表单处理
一、表单输入绑定基础
Vue 3 中通过 v-model 指令实现表单元素与响应式数据的双向绑定,即数据变化时表单元素的值会自动更新,表单元素的值变化时数据也会同步更新。v-model 会根据表单元素的类型自动选择合适的绑定方式。
1.1 文本输入框(text)
<template><div><label>用户名:</label><input type="text" v-model="username"><p>您输入的用户名:{{ username }}</p></div></template><script setup>import { ref } from 'vue'const username = ref('')</script>
对于文本输入框,v-model 绑定的是 value 属性,监听 input 事件。当用户输入内容时,username 会实时更新。
1.2 多行文本框(textarea)
<template><div><label>个人简介:</label><textarea v-model="introduction" rows="3"></textarea><p>简介内容:{{ introduction }}</p><p>字数:{{ introduction.length }}</p></div></template><script setup>import { ref } from 'vue'const introduction = ref('')</script>
多行文本框与单行文本框的使用方式类似,v-model 同样绑定 value 属性和 input 事件。需要注意的是,<textarea> 标签中不要直接写内容作为默认值,应通过 v-model 绑定的变量设置默认值。
1.3 复选框(checkbox)
复选框分为单个复选框和多个复选框两种情况。
单个复选框(绑定布尔值)
<template><div><label><input type="checkbox" v-model="isAgree"> 我已阅读并同意协议</label><p>是否同意:{{ isAgree ? '是' : '否' }}</p><button :disabled="!isAgree">下一步</button></div></template><script setup>import { ref } from 'vue'const isAgree = ref(false)</script>
单个复选框时,v-model 绑定的是布尔值(checked 属性),用于表示是否选中。
多个复选框(绑定数组)
<template><div><label>爱好:</label><div><label><input type="checkbox" v-model="hobbies" value="reading"> 阅读</label><label><input type="checkbox" v-model="hobbies" value="sports"> 运动</label><label><input type="checkbox" v-model="hobbies" value="music"> 音乐</label></div><p>选中的爱好:{{ hobbies.join(', ') }}</p></div></template><script setup>import { ref } from 'vue'const hobbies = ref([])</script>
多个复选框时,v-model 绑定的是数组,数组中会包含所有选中项的 value 值。
1.4 单选按钮(radio)
<template><div><label>性别:</label><div><label><input type="radio" v-model="gender" value="male"> 男</label><label><input type="radio" v-model="gender" value="female"> 女</label></div><p>选中的性别:{{ gender }}</p></div></template><script setup>import { ref } from 'vue'const gender = ref('')</script>
单选按钮组中,v-model 绑定的是选中项的 value 值,同一组单选按钮应绑定同一个变量。
1.5 下拉选择框(select)
下拉选择框分为单选和多选两种情况。
单选下拉框
<template><div><label>城市:</label><select v-model="city"><option value="">请选择城市</option><option value="beijing">北京</option><option value="shanghai">上海</option><option value="guangzhou">广州</option></select><p>选中的城市:{{ city }}</p></div></template><script setup>import { ref } from 'vue'const city = ref('')</script>
单选下拉框中,v-model 绑定的是选中项的 value 值。
多选下拉框(添加 multiple 属性)
<template><div><label>喜欢的颜色(按住 Ctrl 键可多选):</label><select v-model="colors" multiple><option value="red">红色</option><option value="green">绿色</option><option value="blue">蓝色</option><option value="yellow">黄色</option></select><p>选中的颜色:{{ colors.join(', ') }}</p></div></template><script setup>import { ref } from 'vue'const colors = ref([])</script>
多选下拉框需要添加 multiple 属性,v-model 绑定的是数组,数组中包含所有选中项的 value 值。
二、v-model 修饰符
v-model 提供了一些修饰符,用于处理特殊的表单输入场景。
2.1 .lazy
默认情况下,v-model 会在 input 事件中同步输入框的值。使用 .lazy 修饰符后,会改为在 change 事件中同步(即失去焦点或按下回车键时)。
<template><div><input type="text" v-model.lazy="message"><p>message:{{ message }}</p></div></template><script setup>import { ref } from 'vue'const message = ref('')</script>
2.2 .number
.number 修饰符会将输入的值自动转换为数字类型。如果输入的值无法转换为数字,则会返回原始的字符串。
<template><div><input type="text" v-model.number="age"><p>age:{{ age }}</p><p>age 的类型:{{ typeof age }}</p></div></template><script setup>import { ref } from 'vue'const age = ref(0)</script>
在输入框中输入数字时,age 会被转换为 number 类型;输入非数字时,age 会保持 string 类型。
2.3 .trim
.trim 修饰符会自动过滤输入内容首尾的空白字符。
<template><div><input type="text" v-model.trim="username"><p>username:{{ username }}</p><p>username 长度:{{ username.length }}</p></div></template><script setup>import { ref } from 'vue'const username = ref('')</script>
输入内容前后的空格会被自动去除,方便处理用户不小心输入的多余空格。
三、表单验证
在实际开发中,表单提交前需要对输入内容进行验证,确保数据的合法性。可以通过计算属性、侦听器或第三方库(如 VeeValidate)实现表单验证。
3.1 基础验证示例(使用计算属性)
<template><div><form @submit.prevent="handleSubmit"><div><label>用户名:</label><input type="text" v-model="form.username"><span class="error" v-if="errors.username">{{ errors.username }}</span></div><div><label>密码:</label><input type="password" v-model="form.password"><span class="error" v-if="errors.password">{{ errors.password }}</span></div><button type="submit">提交</button></form></div></template><script setup>import { ref, computed } from 'vue'const form = ref({username: '',password: ''})// 验证错误信息const errors = computed(() => {const errors = {}// 验证用户名if (!form.value.username) {errors.username = '用户名不能为空'} else if (form.value.username.length < 3) {errors.username = '用户名长度不能小于 3 位'}// 验证密码if (!form.value.password) {errors.password = '密码不能为空'} else if (form.value.password.length < 6) {errors.password = '密码长度不能小于 6 位'}return errors})// 表单是否有效const isFormValid = computed(() => {return Object.keys(errors.value).length === 0})// 处理表单提交const handleSubmit = () => {if (isFormValid.value) {console.log('表单提交成功:', form.value)// 这里可以添加发送请求的逻辑} else {console.log('表单验证失败')}}</script><style>.error {color: red;margin-left: 10px;font-size: 12px;}</style>
在这个示例中,通过计算属性 errors 实时验证表单数据,并根据验证结果显示错误信息。@submit.prevent 用于阻止表单的默认提交行为,以便手动处理提交逻辑。
3.2 使用第三方库(VeeValidate)
对于复杂的表单验证,推荐使用第三方库(如 VeeValidate),它提供了更丰富的验证规则和更简洁的语法。
安装 VeeValidate
npm install vee-validate@4 @vee-validate/rules@4
基本使用示例
<template><div><Form @submit="handleSubmit"><Field name="email" type="email" label="邮箱" :rules="['required', 'email']" /><ErrorMessage name="email" class="error" /><Field name="password" type="password" label="密码" :rules="['required', { min: 6 }]" /><ErrorMessage name="password" class="error" /><button type="submit">提交</button></Form></div></template><script setup>import { Form, Field, ErrorMessage } from 'vee-validate'import { required, email, min } from '@vee-validate/rules'// 注册验证规则// VeeValidate 4 中无需手动注册,规则会自动识别const handleSubmit = (values) => {console.log('表单提交成功:', values)}</script><style>.error {color: red;font-size: 12px;margin-bottom: 10px;}</style>
VeeValidate 提供了 Form、Field、ErrorMessage 等组件,通过 rules 属性指定验证规则,简化了表单验证的实现。
四、自定义表单控件
有时我们需要创建自定义的表单控件(如评分组件、开关组件等),并让其支持 v-model 双向绑定。要实现这一点,需要在自定义组件中正确处理 value 属性和 input 事件(或自定义事件)。
4.1 自定义开关组件示例
<!-- components/Switch.vue --><template><divclass="switch":class="{ active: isActive }"@click="toggle"><div class="switch-button"></div></div></template><script setup>import { ref, defineProps, defineEmits } from 'vue'// 接收父组件通过 v-model 传递的 valueconst props = defineProps({modelValue: {type: Boolean,default: false}})// 定义 emits,用于向父组件发送事件const emit = defineEmits(['update:modelValue'])// 组件内部的状态const isActive = ref(props.modelValue)// 监听 props 变化,同步到组件内部状态watch(() => props.modelValue, (newValue) => {isActive.value = newValue})// 切换开关状态const toggle = () => {isActive.value = !isActive.value// 触发事件,更新父组件的 v-model 绑定值emit('update:modelValue', isActive.value)}</script><style>.switch {width: 50px;height: 26px;background-color: #ccc;border-radius: 13px;position: relative;cursor: pointer;}.switch.active {background-color: #4cd964;}.switch-button {width: 22px;height: 22px;background-color: white;border-radius: 50%;position: absolute;top: 2px;left: 2px;transition: left 0.3s;}.switch.active .switch-button {left: 26px;}</style>
4.2 使用自定义开关组件
<template><div><label>是否开启通知:</label><Switch v-model="isNotificationEnabled" /><p>通知状态:{{ isNotificationEnabled ? '开启' : '关闭' }}</p></div></template><script setup>import { ref } from 'vue'import Switch from './components/Switch.vue'const isNotificationEnabled = ref(false)</script>
自定义组件通过接收 modelValue 属性获取 v-model 绑定的值,通过触发 update:modelValue 事件更新 v-model 绑定的值,从而实现双向绑定。
五、总结
在实际项目中,应根据表单的复杂程度选择合适的验证方式,对于简单表单可以使用原生的计算属性或侦听器,对于复杂表单推荐使用第三方验证库。同时,合理开发自定义表单控件可以提高组件的复用性和项目的开发效率。