# Vue如何實現表單驗證小功能
## 引言
表單驗證是Web開發中不可或缺的重要環節,它能有效提升用戶體驗和數據準確性。在Vue生態中,我們可以通過多種方式實現靈活的表單驗證功能。本文將深入探討5種主流實現方案,并提供完整的代碼示例和最佳實踐建議。
## 一、基礎HTML5表單驗證
### 1.1 原生HTML5驗證特性
HTML5提供了一系列內置的表單驗證功能,無需JavaScript即可實現基本驗證:
```html
<template>
<form @submit.prevent="submitForm">
<!-- 必填字段驗證 -->
<input
type="text"
v-model="form.name"
required
placeholder="請輸入姓名"
>
<!-- 郵箱格式驗證 -->
<input
type="email"
v-model="form.email"
required
placeholder="請輸入有效郵箱"
>
<!-- 自定義錯誤提示 -->
<input
type="password"
v-model="form.password"
required
minlength="8"
pattern="^(?=.*[A-Za-z])(?=.*\d).+$"
title="密碼需至少8位且包含字母和數字"
>
<button type="submit">提交</button>
</form>
</template>
優點: - 零依賴,無需額外庫 - 瀏覽器原生支持,性能好 - 支持基本的驗證規則(required, pattern, min/max等)
缺點: - 樣式和提示信息難以自定義 - 驗證規則有限 - 兼容性問題(不同瀏覽器表現不一致)
通過CSS可以修改默認的驗證UI:
/* 有效狀態樣式 */
input:valid {
border-color: #42b983;
}
/* 無效狀態樣式 */
input:invalid {
border-color: #ff6464;
}
/* 錯誤提示氣泡 */
input:invalid + .error-message {
display: block;
color: #ff6464;
font-size: 0.8em;
}
創建可復用的驗證指令:
// directives/validate.js
export default {
mounted(el, binding) {
el.addEventListener('blur', () => {
const isValid = binding.value(el.value)
if (!isValid) {
el.classList.add('invalid')
// 顯示錯誤提示
} else {
el.classList.remove('invalid')
}
})
}
}
// main.js
import validateDirective from './directives/validate'
const app = createApp(App)
app.directive('validate', validateDirective)
<template>
<input
v-model="email"
v-validate="validateEmail"
@blur="showError = true"
>
<p v-if="showError && !validateEmail(email)" class="error">
請輸入有效的郵箱地址
</p>
</template>
<script>
export default {
data() {
return {
email: '',
showError: false
}
},
methods: {
validateEmail(value) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)
}
}
}
</script>
npm install @vuelidate/core @vuelidate/validators
import { useVuelidate } from '@vuelidate/core'
import { required, email, minLength } from '@vuelidate/validators'
export default {
setup() {
const form = reactive({
name: '',
email: ''
})
const rules = {
name: { required },
email: { required, email }
}
const v$ = useVuelidate(rules, form)
return { form, v$ }
}
}
<template>
<form @submit.prevent="submitForm">
<div class="form-group">
<label>姓名</label>
<input v-model="form.name">
<span
v-for="error in v$.name.$errors"
:key="error.$uid"
class="error"
>
{{ error.$message }}
</span>
</div>
<button :disabled="v$.$invalid">提交</button>
</form>
</template>
const rules = {
password: {
required,
minLength: minLength(8),
containsUppercase: value => /[A-Z]/.test(value),
containsNumber: value => /\d/.test(value)
}
}
// 自定義錯誤消息
const messages = {
containsUppercase: '密碼必須包含大寫字母',
containsNumber: '密碼必須包含數字'
}
npm install vee-validate@next
import { Form, Field, ErrorMessage } from 'vee-validate'
import * as yup from 'yup'
export default {
components: {
Form,
Field,
ErrorMessage
},
data() {
const schema = yup.object({
email: yup.string().required().email(),
password: yup.string().required().min(8)
})
return {
schema
}
}
}
<template>
<Form :validation-schema="schema" @submit="onSubmit">
<Field name="email" type="email" />
<ErrorMessage name="email" />
<Field name="password" type="password" />
<ErrorMessage name="password" />
<button>提交</button>
</Form>
</template>
異步驗證示例:
const schema = yup.object({
username: yup.string()
.required()
.test('unique', '用戶名已存在', async value => {
return await checkUsernameAvailability(value)
})
})
文件上傳驗證:
const schema = yup.object({
avatar: yup
.mixed()
.test('fileSize', '文件太大', value => {
return value && value.size <= 2000000
})
.test('fileType', '不支持的格式', value => {
return value && ['image/jpeg', 'image/png'].includes(value.type)
})
})
<template>
<el-form
:model="form"
:rules="rules"
ref="formRef"
label-width="120px"
>
<el-form-item label="用戶名" prop="username">
<el-input v-model="form.username"></el-input>
</el-form-item>
<el-form-item>
<el-button type="primary" @click="submitForm">提交</el-button>
</el-form-item>
</el-form>
</template>
export default {
data() {
return {
form: {
username: ''
},
rules: {
username: [
{ required: true, message: '請輸入用戶名', trigger: 'blur' },
{ min: 3, max: 15, message: '長度在3到15個字符', trigger: 'blur' }
]
}
}
},
methods: {
submitForm() {
this.$refs.formRef.validate(valid => {
if (valid) {
// 提交表單
}
})
}
}
}
const validatePassword = (rule, value, callback) => {
if (!value) {
callback(new Error('請輸入密碼'))
} else if (!/[A-Z]/.test(value)) {
callback(new Error('必須包含大寫字母'))
} else {
callback()
}
}
// 在rules中使用
password: [
{ validator: validatePassword, trigger: 'blur' }
]
方案 | 適用場景 | 復雜度 | 維護性 |
---|---|---|---|
HTML5驗證 | 簡單表單、快速原型 | 低 | 低 |
自定義指令 | 需要輕量級解決方案 | 中 | 中 |
Vuelidate | Composition API項目 | 中高 | 高 |
VeeValidate | 復雜表單、企業級應用 | 高 | 高 |
Element Plus | 使用Element UI的項目 | 中 | 中 |
延遲驗證:只在blur或submit時觸發驗證
// VeeValidate示例
<Field name="email" :validate-on-input="false" />
防抖處理: “`javascript import { debounce } from ‘lodash’
methods: { validateInput: debounce(function(value) { // 驗證邏輯 }, 500) }
3. **條件驗證**:動態加載驗證規則
```javascript
computed: {
dynamicRules() {
return this.needsValidation ? { required } : {}
}
}
<template>
<div class="form-group">
<label for="email">郵箱地址</label>
<input
id="email"
v-model="email"
aria-describedby="email-error"
:aria-invalid="hasError"
>
<p id="email-error" v-if="hasError" role="alert">
請輸入有效的郵箱地址
</p>
</div>
</template>
場景:密碼和確認密碼一致性檢查
// VeeValidate解決方案
const schema = yup.object({
password: yup.string().required(),
confirmPassword: yup.string()
.required()
.oneOf([yup.ref('password')], '密碼不匹配')
})
// Element Plus動態規則
watch(() => form.type, (newVal) => {
if (newVal === 'company') {
rules.companyName = [{ required: true }]
} else {
delete rules.companyName
}
})
<Field name="datePicker" v-slot="{ field, errors }">
<el-date-picker
v-bind="field"
:class="{ 'is-invalid': errors.length }"
/>
<span v-if="errors.length" class="error">
{{ errors[0] }}
</span>
</Field>
Vue生態提供了多樣化的表單驗證解決方案,從簡單的HTML5驗證到功能齊全的VeeValidate,開發者可以根據項目需求選擇合適的技術方案。關鍵是要保持驗證邏輯的一致性,提供清晰的錯誤反饋,并確保良好的用戶體驗。
通過本文介紹的五種方法及其組合使用,您應該能夠應對絕大多數表單驗證場景。記住,良好的表單驗證不僅僅是技術實現,更是對用戶體驗的深入思考。
GitHub倉庫鏈接 “`
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。