【Vuetify 3】ログイン画面にバリデーションを追加
目標
サインイン/サインアップ画面にバリデーション処理を追加する
- バリデーションルールの追加
- 各入力情報を送信処理の前にバリデーションを適応させる
事前準備
vue3に事前準備uetify3が導入されたProject
記事では下記Git hub Repositoryを使用する
Vuelidate2の導入
Vuelidate2になって使用感がすごく変わっているので学習コストがかかる気がしてます
yarn add @vuelidate/core @vuelidate/validators
必要なライブラリのインポート
-import { ref, onMounted } from "vue";
+import { ref, reactive, onMounted } from "vue";
+import { useVuelidate } from "@vuelidate/core";
+import { email, required, minLength } from "@vuelidate/validators";
バリデーションの設定
Vuelidateの実装方法を参考
サインイン/サインアップにバリデーションを追加していきます
パスワードのバリデーションは今回最低限にします
値 | バリデーション内容 |
---|---|
必須 メールアドレスのフォーマット | |
password | 必須 最小8文字 |
入力項目のデータを変更
+const state = reactive({
+ email: "",
+ password: "",
+});
-const email = ref("");
-const password = ref("");
入力項目をオブジェクトで管理する事になるので単体で呼び出していた各所をオブジェクトととして呼び出す記述に変更する必要がある
+state.emial
-email
-email.value
ルールを設定したオブジェクトを追加
+// バリデーションルール
+const rules = {
+ email: { required, email },
+ password: { required, minLengthValue: minLength(8) },
+};
入力項目にバリデーションの適応
+// モデルにバリデーションを適応
+const v$ = useVuelidate(rules, state)
v-text-fieldにも項目を追加
イベントハンドラ | 概要 |
---|---|
@input | 入力がされた際にイベントが発火 |
@blur | フォーカスが外れた際にイベントが発火 |
<v-text-field
v-model="state.email"
:label="constant.email"
type="email"
+ :error-messages="v$.email.$errors.map((e) => e.$message)"
+ @input="v$.email.$touch"
+ @blur="v$.email.$touch"
>
</v-text-field>
パスワードの入力項目も同様に修正を行う
実行結果
ボタン押下を行った際にバリデーションチェック実行
サインイン/サインアップを実行した際にバリデーションチェックする
async/awaitで非同期させないとボタンを押下した際にバリデーションチェックを無視してレスポンスを行います
// サインイン処理
-const signin = () => {
+const signin = async () => {
// バリデーションエラー時は処理を停止
+ const isFormCorrect = await v$.value.$validate();
+ if (!isFormCorrect) return;
...
};
// サインアップ処理
-const createAccount = () => {
+const createAccount = async () => {
// バリデーションエラー時は処理を停止
+ const isFormCorrect = await v$.value.$validate();
+ if (!isFormCorrect) return;
...
};
実行結果
ボタンを押下際にメッセージが上手く表示されませんでした。
こちら調べたのですが原因がわかりませんでした。
エラー箇所は赤で表示されるので問題ないと思われますので今回はこのままにします
入力フォームのレイアウトバランス調整
入力フォームの下にエラーメッセージが表示された事で今までのレイアウトだと表示がギチギチになってしまう(エラーメッセージの領域を考慮していなかった自分のミス)ので幅を調整していきますが、スタイルやclassで設定すると、今後他の入力フォームでも同じような調整を求められ修正などに手間が発生するのでv-rowで全体を囲み各入力フォームにv-colを設定していくようにする
<v-col>
<v-text-field
v-model="state.email"
:label="constant.email"
type="email"
:error-messages="v$.email.$errors.map((e) => e.$message)"
@input="v$.email.$touch"
@blur="v$.email.$touch"
>
</v-text-field>
<v-text-field
v-model="state.password"
:label="constant.password"
:type="show ? 'text' : 'password'"
:append-inner-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
@click:append-inner="show = !show"
:error-messages="v$.password.$errors.map((e) => e.$message)"
@input="v$.password.$touch"
@blur="v$.password.$touch"
>
</v-text-field>
<v-btn color="primary" variant="tonal" @click="signin">
{{ constant.signin }}
</v-btn>
<v-btn color="primary" variant="tonal" @click="createAccount">
{{ constant.sinup }}
</v-btn>
</v-col>
<v-row>
<v-col cols="12">
<v-text-field
v-model="state.email"
:label="constant.email"
type="email"
:error-messages="v$.email.$errors.map((e) => e.$message)"
@input="v$.email.$touch"
@blur="v$.email.$touch"
>
</v-text-field>
</v-col>
<v-col cols="12">
<v-text-field
v-model="state.password"
:label="constant.password"
:type="show ? 'text' : 'password'"
:append-inner-icon="show ? 'mdi-eye' : 'mdi-eye-off'"
@click:append-inner="show = !show"
:error-messages="v$.password.$errors.map((e) => e.$message)"
@input="v$.password.$touch"
@blur="v$.password.$touch"
>
</v-text-field>
</v-col>
<v-col cols="12">
<v-btn color="primary" variant="tonal" @click="signin">
{{ constant.signin }}
</v-btn>
<v-btn color="primary" variant="tonal" @click="createAccount">
{{ constant.sinup }}
</v-btn>
</v-col>
</v-row>
Vuelidate2メリット
ビルトインがある事で必須項目やメールアドレスなど、自分で実装するにはバグを発生させたくない部分を確実に実装できる
Vuelidate2デメリット
テンプレートにイベントハンドラやエラーメッセージに値を渡してあげる処理を追加する必要がある
エラーメッセージを日本語に変更する処理が別途必要(現在未実装)
Git commit情報
今回の修正は量が多いので全体を確認したい場合はcommit履歴を確認しましょう
SHA | commit message |
---|---|
9c48b82 | 【Vuetify 3】ログイン画面にバリデーションを追加 |
あとがき
別途メッセージの日本語化の記事を作成する
Vuelidateは2になってから使用感が大幅に変わった。
扱いにくくはなった気がするがビルトイン機能はすごく助かるので使わないわけにはいかない
Discussion