Lala Code

Lala 的前端大補帖,歡迎一起鑽研前端技術😊

0%

vee-validate 4.0 教學,表單驗證套件應用

vee-validate

填寫表單時,需要驗證是否必填(require)、或是格式是否正確,自己手刻很複雜,可能也會不夠全面,用套件來做驗證是最省事又快速的。在 Vue2 框架時,我偏好使用 vee-validate 來做驗證,因為它簡單又好用,但到了 Vue3,veeValidate4 怎麼好像是另一個世界惹😱,vee-validate4 該怎麼使用呢

安裝 vee-validate

首先先安裝 vee-validate

1
2
3
yarn add vee-validate
# or
npm i vee-validate --save

另外 yup 也是個簡單卻強大的驗證 library,vee-validate 可以結合 yup 一起使用

安裝 yup

1
2
3
yarn add yup
# or
npm i yup --save

使用 vee-validate

vee-validate 提供了兩種方法,可以使用 components 或是 composition API
components: 適合簡單的 UI 組件和具有自定義樣式的原生 HTML 元素,使用 Field、Form 和 ErrorMessage
composition API: 適合構建複雜的 UI 表單組件和通用數據驗證,使用 useField、useForm
這兩種方式都可以混合使用

我這邊使用的是 composition API + yup 來做驗證



製作需求:
1.取得 API 資料後,會自動把資料帶入到表單
2.表單驗證
3.取得表單值


引入驗證 js、input 元件

在 main.js 引入全局 (global) 驗證、表單 component input,如果表單只有一頁,可以直接引用在表單頁面
main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'

const app = createApp(App);

// 引入全局驗證、表單 component input
import { schema } from '@/utils/validate.js';
app.provide('schema', schema);
import FormInput from '@/components/FormInput.vue';
app.component('FormInput', FormInput);

app.use(router).mount('#app')

用 yup 處理驗證格式的 js

.required 必填
.matches 客製驗證格式
.oneOf 確認 key 是否相同
.min 最少幾位數
.max 最多幾位數
.nullable 接受 key 為 null

utils/validate.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { object, string, ref, array } from 'yup';
const required = '必填';
const phoneRegExp = /^((\\+[1-9]{1,4}[ \\-]*)|(\\([0-9]{2,3}\\)[ \\-]*)|([0-9]{2,4})[ \\-]*)*?[0-9]{3,4}?[ \\-]*[0-9]{3,4}?$/;
const passwordRegExp = /[a-zA-Z0-9]/;

export const schema = object().shape({
email: string().required(required).email('E-mail輸入錯誤'),

password: string()
.required(required)
.min(8, '密碼最少8位')
.max(20, '密碼最多20位')
.matches(passwordRegExp, '請輸入不含符號的半形英文、數字'),

confirmPassword: string()
.oneOf([ref('password')], '輸入密碼不相同')
.required(required),

phone: string().matches(phoneRegExp, '手機輸入錯誤'),

userName: string().nullable().required(required),

link: array().of(string().required('請輸入標題')),
});

建立 input 元件

設定從父層來的 props

components/FormInput.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<template>
<input
:id="id"
v-model="inputValue"
:name="name"
:type="type"
:placeholder="placeholder"
:maxlength="maxlength"
class="form-control"
:class="{ 'is-invalid': errorMessage }"
/>
<div class="invalid-feedback">{{ errorMessage }}
</div>
</template>

並設定 useField 的值 (value) 跟錯誤訊息 (errorMessage),會由 name 來判定驗證格式是否正確,watch 是為了取得 API 資料後,會自動把資料帶入到表單,如沒有這個需求可以拿掉

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import { useField } from 'vee-validate';
import { watch } from 'vue';

export default {
props: {
name: {
type: String,
required: true,
},
id: {
type: String,
default: '',
},
type: {
type: String,
default: '',
},
modelValue: {
type: String,
default: '',
},
placeholder: {
type: String,
default: '',
},
maxlength: {
type: Number,
default: Infinity,
},
},
setup(props) {
let { value: inputValue, errorMessage } = useField(
props.name,
undefined,
{
// 設定預設值,如未設定值為 undefined
initialValue: props.modelValue,
}
);

// 取得 API 資料後,會自動把資料帶入到表單
watch(
() => props.modelValue,
val => {
inputValue.value = val;
}
);

return {
inputValue,
errorMessage,
};
},
};

表單頁面

插入 input component,設定好要傳入的 props

Form.vue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
<template>
<div class="form-box">
<div>
<div class="form-group">
<label for="userName">姓名:</label>
<FormInput
:id="'userName'"
v-model="memberInfo.data.name"
:name="'userName'"
:type="'text'"
:placeholder="'輸入'"
/>
</div>
<div class="form-group">
<label for="password">密碼:</label>
<FormInput
:id="'password'"
v-model="password.password"
:name="'password'"
:type="'password'"
:placeholder="'輸入'"
/>
</div>
<div class="form-group">
<label for="confirmPassword">確認密碼:</label>
<FormInput
:id="'confirmPassword'"
v-model="password.confirmPassword"
:name="'confirmPassword'"
:type="'password'"
:placeholder="'輸入'"
/>
</div>
<div class="form-group">
<label for="email">e-mail:</label>
<FormInput
:id="'email'"
v-model="memberInfo.data.email"
:name="'email'"
:type="'text'"
:placeholder="'輸入'"
/>
</div>
<div>
<div v-for="(item, idx) in fields" :key="item.url" class="form-group">
<label :for="`link${idx}`">link{{idx+1}}:</label>
<FormInput
:id="`link[${idx}]`"
:name="`link[${idx}].url`"
:type="'text'"
:placeholder="'輸入'"
/>
<button type="button" @click="remove(idx)">remove</button>
</div>
<button type="button" @click="push({url: ''})">add</button>
</div>
</div>
</div>
<div>
Form 表單取值:
{{ values }}
</div>
</template>

設定 useForm、useFieldArray
useForm 是整個 Form 表單,設定驗證並取值,取到的值 submit 到後端,就資料完成送出啦!
useFieldArray 用來設定陣列的 input,可使用內建方法:移除 (remove)、取代 (replace)、新增資料 (push)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
import { reactive, inject } from 'vue';
import { useForm, useFieldArray } from 'vee-validate';
import axios from 'axios';

export default {
setup() {
const schema = inject('schema');

// 整個 Form 表單
const { values } = useForm({
validationSchema: schema,
});

// 設定多筆資料的陣列、陣列方法
const { replace, remove, push, fields } = useFieldArray('link');

const password = reactive({
password: '',
confirmPassword: '',
});

// 取得 API 的資料
const publicPath = process.env.BASE_URL;
const getMemberInfo = () => {
return axios.get(`${publicPath}data/info.json`);
};

let memberInfo = reactive({
data: {}
});

getMemberInfo().then(res => {
memberInfo.data = res.data;
// 取得資料後,將空陣列資料取代為取得後的資料
replace(memberInfo.data.link);
});

return {
password,
memberInfo,
values,
remove, push, fields
}
}
}
1
2
3
4
5
6
7
8
9
10
11
.form-box {
display: flex;
justify-content: center;
align-items: center;
height: 100%;
}

.form-group {
margin: 20px 0;
display: flex;
}

資料格式
data/info.json

1
2
3
4
5
6
7
8
{
"name": "bobee",
"email": "lala9990929@gmail.com",
"link": [
{ "url": "https://happy9990929.github.io"},
{ "url": "https://happy9990929.github.io/gtplay"}
]
}

結語

vee-validate4.0 跟之前的版本差異真的很大,我也是研究了一陣子,如果有哪邊有問題或是有更好的寫法,歡迎路過的大大指正噢🧐
👉 附上我的 vee-validate4 範例
最後用可愛的 bobee 做結尾吧!


bobee


參考文獻

vee-validate 官方



Hey!想學習更多前端知識嗎?

最近 Lala 開了前端課程 👉【實地掌握RWD - 12小時新手實戰班】👈
無論您是 0 基礎新手,又或是想學 RWD 的初學者,
我們將帶你從零開始,深入了解並掌握 RWD 響應式網頁設計的核心技術,快來一起看看吧 😊



🚀線上課程分享

線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程
想學習更多關於前後端的線上課程,可以參考看看。

Hahow

Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住



六角學院

如果你是初學者,非常推薦六角學院哦!
剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!


Udemy

Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!
也是很多工程師推薦的線上課程網站。
❤️