文章大綱
如果我們使用ui框架,通常都會有封裝好的form可以幫你驗證。
但是如果你沒有使用ui框架,驗證的效果就要自己寫囉!
validate.js的使用方法可以先參考官網,因為這邊只會介紹最基本的XD
首先你要先有一個vue3的專案。
安裝validate.js
$ yarn add validate.js
創建方法
把每次需要創建表單的方法包成composable。
新增一隻檔案在composables/validate.js
import { reactive } from "vue";
import Validate from "validate.js";
export const useValidate = ({ defaultFormModel, constraints }) => {
const formModel = reactive({ ...defaultFormModel });
const errorText = reactive({ ...defaultFormModel });
const handleValid = () => {
// 等等我們要實作的驗證方法
};
return { formModel, errorText, handleValid };
};
我們會根據頁面的需要傳入defaultFormModel,是一個單純的物件,他的內容就是表單的欄位:
const defaultFormModel = {
username: '',
password: '',
code: ''
};
formModel和errorText初始值都會是表單的欄位:
formModel是畫面中input要用v-model綁定的地方;errorText是當驗證出錯時,要顯示的錯誤訊息,也就是說errorText裡面的某個key的值是空的話,代表他驗證通過囉!
const formModel = reactive({ ...defaultFormModel });
const errorText = reactive({ ...defaultFormModel });
constraints就是要驗證的規則,假設我傳入的欄位需要驗證,就這樣輸入:
const constraints = {
username: {
presence: {
allowEmpty: false,
message: "請輸入電子郵件或手機號碼",
},
},
password: {
presence: {
allowEmpty: false,
message: "請輸入英數字混合密碼8~16位",
},
format: {
pattern: "[a-z0-9]{8,16}$",
flags: "i",
message: "請輸入英數字混合密碼8~16位",
},
},
code: {
presence: {
allowEmpty: false,
message: "請輸入驗證碼",
},
}
}
handleValid是驗證方法,裡面就是直接呼叫validate.js的實例了:
import Validate from "validate.js";
//...
const handleValid = () => {
const res = Validate(formModel, constraints,
{
fullMessages: false,
}
);
res &&
Object.keys(errorText).forEach((i) => {
errorText[i] = res[i]?.[res[i].length - 1] || "";
});
res ||
Object.keys(errorText).forEach((i) => {
errorText[i] = "";
});
return res;
}
目前這個方法可以用在按下「送出」按鈕後,直接先驗證表單所有欄位。
但是我們會需要在單獨輸入某個欄位時,只驗證那個欄位。
這時候就可以用validate.single這個方法,或者自己改寫XD
我們在handleValid多一個參數傳入,傳入的我們希望他是要驗證的欄位名稱們,是一個陣列:
const attributes = ['username', 'password'];
const handleValid = (attributes) => {
const validAttributes = attributes || Object.keys(errorText);
const res = Validate(
formModel,
getObjectKeys(constraints, validAttributes),
{
fullMessages: false,
}
);
res &&
validAttributes.forEach((i) => {
errorText[i] = res[i]?.[res[i].length - 1] || "";
});
res ||
validAttributes.forEach((i) => {
errorText[i] = "";
});
return res;
};
其中getObjectKeys方法只是我一個轉換的util,它的作用是:
const constraints = {
username: {
//...
},
password: {
//...
},
code: {
//...
}
}
getObjectKeys(constraints, ['username', 'password'];
// output--> { username: {...}, password:{...} };
改寫後,當我們的input組件再輸入的時候也可以呼叫這個方法,只要再多傳入要驗證的欄位陣列就好。
頁面中使用
在畫面中我們會有input組件和@input方法:
<Input
v-model="formModel.name"
:errorText="errorText.name"
placeholder="請輸入姓名"
label="姓名"
@handleOnInput="handleValid(['name'])"
/>
setup(){
const { formModel, errorText, handleValid } = useValidate({
defaultFormModel,
constraints,
});
return {
formModel,
errorText,
handleValid,
};
}
<Input />這個組件是我自己封裝的,你也可以自己封裝外觀,我的原理是:errorText.name有東西的話就會顯示紅匡+錯誤訊息。訊息內容當然就是errorText.name的值囉!
@handleOnInput也是封裝的,他在底層是:
<input @input="handleOnInput" />
//...
const handleOnInput = () => {
//...
emit("handleOnInput");
};
送出表單,先驗證全部欄位:
<button @click="handleSubmit">送出</button>
//...
const handleSubmit = () => {
const validRes = handleValid();
if (validRes) return;
// 寫入登入資訊
// 回到首頁
};
完整程式碼
<template>
<div class="auth">
<h1>會員登入</h1>
<Input
v-model:inputText="formModel.username"
:errorText="errorText.username"
placeholder="電子郵件或手機號碼登入"
label="電子郵件或手機"
@handleOnInput="handleValid(['username'])"
/>
<Input
v-model:inputText="formModel.password"
:errorText="errorText.password"
placeholder="密碼"
label="密碼"
@handleOnInput="handleValid(['password'])"
/>
<input
type="checkbox"
v-model="formModel.remember"
/>
<button @click="handleSubmit">登入</button>
</div>
</div>
</template>
<script>
import Input from "@/components/Form/Input";
import { useStore } from "vuex";
import { useRouter } from "vue-router";
import { username, password } from "@/utils/validateRules";
import { useValidate } from "@/composables/validate";
import { computed } from "@vue/runtime-core";
const defaultFormModel = {
username: "",
password: "",
remember: true,
};
const constraints = {
username,
password,
};
export default {
components: { Input },
setup() {
const store = useStore();
const router = useRouter();
const { formModel, errorText, handleValid } = useValidate({
defaultFormModel,
constraints,
});
const handleSubmit = () => {
const validRes = handleValid();
if (validRes) return;
// store.commit("auth/setUser", { ...formModel });
// router.push({ name: "Home" });
};
return {
formModel,
errorText,
handleValid,
handleSubmit,
};
},
};
</script>
import { reactive } from "vue";
import Validate from "validate.js";
import { getObjectKeys } from "@/utils";
export const useValidate = ({ defaultFormModel, constraints }) => {
const formModel = reactive({
...defaultFormModel,
});
const errorText = reactive({ ...defaultFormModel });
const handleValid = (attributes) => {
const validAttributes = attributes || Object.keys(errorText);
const res = Validate(
formModel,
getObjectKeys(constraints, validAttributes),
{
fullMessages: false,
}
);
res &&
validAttributes.forEach((i) => {
errorText[i] = res[i]?.[res[i].length - 1] || "";
});
res ||
validAttributes.forEach((i) => {
errorText[i] = "";
});
return res;
};
return { formModel, errorText, handleValid };
};
export const username = {
presence: {
allowEmpty: false,
message: "請輸入電子郵件或手機號碼",
},
};
export const password = {
presence: {
allowEmpty: false,
message: "請輸入英數字混合密碼8~16位",
},
format: {
pattern: "[a-z0-9]{8,16}$",
flags: "i",
message: "請輸入英數字混合密碼8~16位",
},
};
export const name = {
presence: {
allowEmpty: false,
message: "請輸入姓名",
},
};
export const phone = {
presence: {
allowEmpty: false,
message: "請輸入電話號碼",
},
format: {
pattern: "^09[0-9]{8}$",
flags: "i",
message: "請輸入09開頭的10位數字手機號碼",
},
};
export const verifyCode = {
presence: {
allowEmpty: false,
message: "請輸入認證碼",
},
numericality: { onlyInteger: true, message: "請輸入正確的認證碼" },
length: {
is: 6,
message: "請輸入正確的認證碼",
},
};
export const email = {
presence: {
allowEmpty: false,
message: "請輸入Email",
},
email: {
message: "請輸入合法的電子郵件",
},
};





發表評論
想要加入討論嗎?請盡情發表您的想法!