🐥
vee-validate(useForm とuseField)でバリデーションした時の備忘録
Register.vueファイルに実装した時を例に書いてます。
自分のファイルに置き換えながら進めてください。
main.ts
main.tsに以下を書くことでグローバルでバリデーション使える様に設定してます。
main.ts
// vee-validateバリデーションの設定
import { defineRule, configure } from 'vee-validate'
import { localize } from '@vee-validate/i18n'
import ja from '@vee-validate/i18n/dist/locale/ja.json'
import AllRules from '@vee-validate/rules'
Object.keys(AllRules).forEach((rule) => {
defineRule(rule, AllRules[rule])
})
configure({
generateMessage: localize({
ja
})
})
localize('ja')
// ここまでvee-validate
-
AllRules
で全てのルールを有効化 -
vee-validate/i18n
でエラーメッセージを日本語化
Register.vue
- インポートはこの2つ
import { useField, useForm } from 'vee-validate'
import { object, string, setLocale } from 'yup'
yupはバリデーション用のライブラリ。
useFieldでinputタグと紐付け
const { value: department } = useField('department')
const { value: email } = useField('email')
const { value: password } = useField('password')
- useFieldは特定のフォームフィールドのバリデーション状態と関連する情報を取得できます。第1引数=フィールド名、第2引数=バリデーション関数が入ります。今回はバリデーションは別で(yupで)つけるので第2引数は不要です。valueはv-modelの値です。
useFormでフォーム全体にバリデーションを作用させる
const { errors } = useForm({
validationSchema: schema,
initialValues: {
department: '',
email: '',
password: '',
}
})
//エラーメッセージの表示はtemplateの中で以下のように使える
<p class="text-red-500">{{ errors.email }}</p>
- useFormを使うことで複数の入力箇所に一括でバリデーションをつけられます。イメージは、useFieldは1つのiuputに対して作用。useFormは(複数のiuputまとめてる)formタグ対して作用するイメージ。
- initialValueは必要なら記載。
- validationSchemaにschemaを設定することでバリデーションができる。
↓schemaの設定は次の通り
schemaでつけたいバリデーションを設定する
const schema = object({
department: string().required().label('所属区分'),
email: string().required().email().label('メールアドレス'),
password: string().required().label('パスワード').min(4),
})
- schemaで各inputに対してつけたいバリデーションを設定します。
string()=文字列のバリデーション
required()=必須入力のバリデーション
email()=メールアドレス形式のバリデーション
min()=最低文字数のバリデーション
↓なんのバリデーションがあるのかは以下の記事を参照
setLocaleでエラーメッセージの設定
setLocale({
mixed: {
default: '不正な値です。',
required: ({ label }) => `${label}は必須の項目です。`
},
string: {
email: ({ label }) => `${label}の形式ではありません。`,
min: ({ label, min }) => `${label}は${min}以上入力してください。`
}
})
-
required: ({ label }) => ${label}は必須の項目です。
であれば入力がなかった場合、「所属区分(labelの文字)は必須の項目です。」とメッセージが表示される。 -
mixed
はyupのlocale.d.tsファイルのMixedLocale
を指しています。string
ならStringLocale
。どのLocaleになんのバリデーションがあるかも、上記の記事を参照するとわかりやすいです。 -
エラーメッセージの設定はsetLocaleを使わなくてもschemaの中に直接設定することもできます。
department: string().required('所属区分は必須の項目です。').label('所属区分'),
required()みたいに()の中にメッセージを設定。
作業は終わりです!
templateは以下を参照してください。
コード例(ユーザー登録フォーム)
main.ts
// import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
import '@/index.css'
import { library } from '@fortawesome/fontawesome-svg-core'
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
import {
faEye,
faEyeSlash,
faDesktop,
faMobileScreenButton
} from '@fortawesome/free-solid-svg-icons'
library.add(faEye, faEyeSlash, faDesktop, faMobileScreenButton)
// vee-validateバリデーションの設定
import { defineRule, configure } from 'vee-validate'
import { localize } from '@vee-validate/i18n'
import ja from '@vee-validate/i18n/dist/locale/ja.json'
import AllRules from '@vee-validate/rules'
Object.keys(AllRules).forEach((rule) => {
defineRule(rule, AllRules[rule])
})
configure({
generateMessage: localize({
ja
})
})
localize('ja')
// ここまでvee-validate
const app = createApp(App)
app.use(router).component('font-awesome-icon', FontAwesomeIcon)
app.mount('#app')
Register.Vue
<script setup lang="ts">
import WhiteButton from '@/components/ui/button/WhiteButton.vue'
import { ref } from 'vue'
import { useField, useForm } from 'vee-validate'
import { object, string, setLocale } from 'yup'
let isShow = ref('password')
// パスワード表示切り替え
const onClick = () => {
if (isShow.value === 'password') {
isShow.value = 'text'
} else if (isShow.value === 'text') {
isShow.value = 'password'
}
}
setLocale({
mixed: {
default: '不正な値です。',
required: ({ label }) => `${label}は必須の項目です。`
},
string: {
email: ({ label }) => `${label}の形式ではありません。`,
min: ({ label, min }) => `${label}は${min}以上入力してください。`
}
})
const schema = object({
lastName: string().required().label('姓名'),
firstName: string().required().label('姓名'),
hireDate: string().required().label('入社月'),
department: string().required().label('所属区分'),
// email: string().required().email().label('メールアドレス'),
password: string().required().label('パスワード').min(4),
confirmPassword: string().required().label('確認パスワード').min(4)
})
const { errors, handleSubmit, isSubmitting } = useForm({
validationSchema: schema,
initialValues: {
lastName: '',
firstName: '',
hireDate: '',
department: '',
email: '',
password: '',
confirmPassword: ''
}
})
const { value: lastName } = useField('lastName')
const { value: firstName } = useField('firstName')
const { value: hireDate } = useField('hireDate')
const { value: department } = useField('department')
const { value: email } = useField('email')
const { value: password } = useField('password')
const { value: confirmPassword } = useField('confirmPassword')
const onSubmit = handleSubmit((values, { resetForm }) => {
console.log(values)
resetForm()
})
</script>
<template>
<body>
<div class="border-2 border-darkBlue w-2/5 mx-auto my-44 rounded-md">
<h1 class="title text-3xl text-center my-10">新規ユーザー登録画面</h1>
<form @submit="onSubmit" class="text-center">
<div class="mb-2">
<label for="lastName">      姓 </label>
<input
id="lastName"
type="text"
placeholder=""
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
v-model="lastName"
/>
<p class="text-red-500">{{ errors.lastName }}</p>
</div>
<div class="mb-2">
<label for="firstName">      名 </label>
<input
id="firstName"
type="text"
placeholder=""
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
v-model="firstName"
/>
<p class="text-red-500">{{ errors.firstName }}</p>
</div>
<div class="mb-2">
<label for="hireDate">   入社年月 </label>
<input
id="hireDate"
type="month"
placeholder=""
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
v-model="hireDate"
/>
<p class="text-red-500">{{ errors.hireDate }}</p>
</div>
<div class="mb-2">
<label for="department">   所属区分 </label>
<select
id="department"
v-model="department"
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
>
<option selected value="">所属区分を選択してださい</option>
<option value="java">Java</option>
<option value="php">PHP</option>
<option value="cl">CL</option>
<option value="ml">ML</option>
<option value="fr">FR</option>
<option value="qa">QA</option>
</select>
<p class="text-red-500">{{ errors.department }}</p>
</div>
<div class="mb-2">
<label for="email">メールアドレス </label>
<input
disabled
id="email"
type="email"
placeholder="power.taro@rakus-partners.co.jp"
class="w-1/2 h-9 mx-auto text-sm px-2"
v-model="email"
/>
<p class="text-red-500">{{ errors.email }}</p>
</div>
<div class="mb-2">
<label for="email">  パスワード </label>  
<input
id="password"
:type="isShow"
placeholder=""
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
v-model="password"
/><button type="button" @click="onClick">表示</button>
<p class="text-red-500">{{ errors.password }}</p>
</div>
<div class="mb-2">
<label for="confirmPassword">確認パスワード </label>
<input
id="confirmPassword"
type="password"
placeholder=""
class="border border-gray-800 rounded w-1/2 h-9 mx-auto text-sm px-2"
v-model="confirmPassword"
/>
<p class="text-red-500">{{ errors.confirmPassword }}</p>
</div>
<WhiteButton
type="submit"
:disabled="isSubmitting"
label="登録"
class="w-2/3 my-7 mx-auto text-blue-500 font-bold text-sm rounded-md"
/>
</form>
</div>
</body>
</template>
Discussion