Vee-Validate 4 表單驗證簡單上手
在開發中驗證表單欄位是一件前後端都必須處理的事情,不僅前端要驗證使用者輸入的欄位資訊,後端也要驗證送往伺服器的資料。
而前端的驗證如果要自己寫,會牽扯到正則,而且也會容易掛一漏萬,所以如果要在 Vue 裡面進行表單驗證,通常會引用套件,但是並不是所有的套件都支援中文語系。
Vee-Validate 是目前比較完整而且支援繁體中文語系的驗證套件。雖然說是套件,如果你去看 Vee-Validate 的官網,保證看完了,還是一頭霧水。所以我整理了 Vee-Validate 的使用方法,以防自己下次要用又失憶了。
Vee-Validate 官網:https://vee-validate.logaretm.com/v4/
因為目前我所使用的是 Vue 3 的版本,所以要搭配 Vee-Validate 4.0 以上版本,在安裝的時候要注意版本相匹配的問題。
安裝 Vee-Validate
安裝時除了 Vee-Validate 主程式之外,還要安裝驗證規則(rules)及多國語系(i18n)。
npm i vee-validate @vee-validate/i18n @vee-validate/rules @vee-validate/i18n --save
只要在 main.js 中設定,多國語系(i18n)就會把驗證的錯誤訊息轉成繁體中文。
例如: “email”: “{field} 須為有效的電子信箱”, {field} 的部分會填入對應的欄位名稱。
main.js 設定
在 main.js 中引入套件之外,同時把相關的規則及元件做全域註冊,就不用在每個需要做驗證的 vue 檔案中一一匯入。
import { createApp } from "vue";
import { createPinia } from "pinia";
import App from "./App.vue";
import router from "./router";
// 匯入 vee-validate 主套件
import { Field, Form, ErrorMessage, defineRule, configure } from "vee-validate";
// 匯入 vee-validate 相關規則
import {
required,
email,
min,
numeric,
max_value,
min_value,
between,
digits
} from "@vee-validate/rules";
// import * as rules from '@vee-validate/rules';
// 匯入多國語系的功能
import { localize, setLocale } from "@vee-validate/i18n";
// 匯入繁體中文語系檔案
import zhTW from "@vee-validate/i18n/dist/locale/zh_TW.json";
const app = createApp(App);
// 定義驗證規則
defineRule("required", required);
defineRule("email", email);
defineRule("min", min);
// 數字,但是小數點會認為是非數字
defineRule("numeric", numeric);
defineRule("max_value", max_value);
defineRule("min_value", min_value);
// between 可以驗證 某個區間的數字,例如 5~10
defineRule("between", between);
// digits 限制小數點後幾位數
defineRule("digits", digits);
// 設定 vee-validate 全域規則
configure({
generateMessage: localize({ zh_TW: zhTW }), // 載入繁體中文語系
validateOnInput: true, // 當輸入任何內容直接進行驗證
});
// 設定預設語系
setLocale("zh_TW");
// 註冊 vee-validate 三個全域元件
app.component("Form", Form);
app.component("Field", Field);
app.component("ErrorMessage", ErrorMessage);
app.mount("#app");
也可以使用這種方法把全部的規則都引入,就不用像上面一樣一一定義驗證規則。
import { defineRule } from 'vee-validate';
import * as rules from '@vee-validate/rules';
Object.keys(rules).forEach(rule => {
defineRule(rule, rules[rule]);
});
表單欄位的設定
表單的頭尾要用大寫 F 開頭的 <Form>
包住, v-slot=”{ errors }”
則對應到錯誤訊息欄位。
<Form ref="form" @submit="submitOrders" v-slot="{ errors }">
</Form>
原本的 <input>
Z標籤用 name
會對應到 name
,如果欄位輸入錯誤,以 email 欄位為例,就會出現:「email 為必填」。
rules="email|required"
則會去抓 main.js 中定義的表單規則。
:class="{ 'is-invalid': errors['email'] }"
輸入驗證錯誤則會綁定 Bootstrap 中 is-invalid 樣式,讓輸入框的 border 變成紅色的。
<Field id="email" name="email" type="email" class="form-control" rules="email|required" :class="{ 'is-invalid': errors['email'] }" placeholder="請輸入 Email" v-model="form.user.email"></Field>
<ErrorMessage name="email" class="invalid-feedback"></ErrorMessage>
<button>
的 disabled
有綁訂到 Vee-Validate 的 errors
物件,如果陣列長度大於 0,按鈕就不能按。
<button type="submit" class="btn btn-lg w-100 add-btn" @submit="submitOrders" :disabled="Object.keys(errors).length > 0">
送出訂單
</button>
<Form ref="form" @submit="submitOrders" v-slot="{ errors }">
<div class="mb-3">
<label for="email" class="form-label">Email<span class="form-note">*</span></label>
<Field id="email" name="email" type="email" class="form-control" rules="email|required" :class="{ 'is-invalid': errors['email'] }" placeholder="請輸入 Email" v-model="form.user.email"></Field>
<ErrorMessage name="email" class="invalid-feedback"></ErrorMessage>
</div>
<div class="mb-3">
<label for="name" class="form-label">收件人姓名<span class="form-note">*</span></label>
<Field id="name" name="姓名" type="text" class="form-control" :class="{ 'is-invalid': errors['姓名'] }" placeholder="請輸入姓名" rules="required" v-model="form.user.name"></Field>
<ErrorMessage name="姓名" class="invalid-feedback"></ErrorMessage>
</div>
<div class="mb-3">
<label for="tel" class="form-label">收件人電話<span class="form-note">*</span></label>
<Field id="tel" name="電話" type="text" class="form-control" :rules="isPhone" :class="{ 'is-invalid': errors['電話'] }" placeholder="請輸入電話" v-model="form.user.tel"></Field>
<ErrorMessage name="電話" class="invalid-feedback"></ErrorMessage>
</div>
<div class="mb-3">
<label for="address" class="form-label">收件人地址<span class="form-note">*</span></label>
<Field id="address" name="地址" type="text" class="form-control" :class="{ 'is-invalid': errors['地址'] }" placeholder="請輸入地址" rules="required" v-model="form.user.address"></Field>
<ErrorMessage name="地址" class="invalid-feedback"></ErrorMessage>
</div>
<div class="mb-3">
<label for="message" class="form-label">留言</label>
<textarea id="message" class="form-control" cols="30" rows="10" v-model="form.message"></textarea>
</div>
<div class="text-end">
<button type="submit" class="btn btn-lg w-100 add-btn" @submit="submitOrders" :disabled="Object.keys(errors).length > 0">
送出訂單
</button>
</div>
</Form>
Script 中的設定
表單的 v-model
有綁訂到 data 的 form 物件。 button 綁定的 submitOrders 方法是打 API 把訂單送去後端。
data () {
return {
form: {
user: {
name: '',
email: '',
tel: '',
address: ''
},
message: ''
},
}
},
其中手機號碼的驗證規則,也寫在 methods 裡面:
methods: {
// validate
isPhone (value) {
const phoneNumber = /^(09)[0-9]{8}$/
return phoneNumber.test(value) ? true : '需要正確的電話號碼'
},
}
久久寫一次驗證,發覺自己有點失意,寫個筆記,希望下次可以不用花那麼久的時間重新探索。
參考: