🐝

[Vue3]VeeValidate4でinput type="file"のバリデーション

2024/06/19に公開

概要

業務でVue2->Vue3のプロジェクトに参画しており、VeeValidate3で実装していたinput type=fileのバリデーションの移行にハマってしまったため備忘として残します。
なお筆者はフロント経験は浅く、ご指摘など滝のようにいただけますと幸いです。

やりたいこと

画像ファイルのアップロードができるコンポーネントで、バリデーションルールが文字列で size:2000|mimes:image/*のように指定される。
inputの@changeイベントで選択されたファイルに対し指定のルールでバリデーションをかけて、エラーであればエラーメッセージを表示したい。
バリデーションルールは自作せずにVeeValidate組み込みのルールを使用したい。

実装

'size:2000|mimes:image/*'という文字列のルールで、2000KBまでの画像に制限するバリデーションを行いたいとします。

template

<template>
<div>
  <h1>ファイルを選択</h1>
  <input type="file" @change="handleFileChange" />
  <p>{{ errorMessage }}</p>
</div>
</template>

例として簡単に記述します。特にVeeValidate関連の記述はありません。

script

import { defineRule, useField } from 'vee-validate'
import { mimes, size } from '@vee-validate/rules'

VeeValidateから必要なものをインポートします。
上記のmimes, sizeが、それぞれファイルを画像に制限する・ファイルサイズを制限するための組み込みのルールです。
利用できるルールは以下に記載があります。
https://vee-validate.logaretm.com/v4/guide/global-validators#available-rules

defineRule('size', size)
defineRule('mimes', mimes)

文字列で指定されるルールのsize mimesをそれぞれ組み込みのルールに紐づけるためにdefineRuleで定義します。

const { value, validate, errorMessage } = useField('file', 'size:2000|mimes:image/*')

useFieldの第2引数にルールを渡し、対象のファイルデータを格納するvalue、バリデーションを実行するメソッドのvalidate、バリデーションがエラーとなった場合のエラーメッセージが格納されるerrorMessageを取得します。

const handleFileChange = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return
  value.value = file
  await validate()
}

inputの@changeイベントで発火し、useFieldで取得したvalueにeventのファイルを格納してvalidate()を実行するメソッドを定義します。

app.vue
<script setup lang="ts">
import { defineRule, useField } from 'vee-validate'
import { mimes, size } from '@vee-validate/rules'

defineRule('size', size)
defineRule('mimes', mimes)

const { value, validate, errorMessage } = useField('file', 'size:2000|mimes:image/*')

const handleFileChange = async (event: Event) => {
  const target = event.target as HTMLInputElement
  const file = target.files?.[0]
  if (!file) return
  value.value = file
  await validate()
}
</script>
<template>
<div>
  <h1>ファイルを選択</h1>
  <input type="file" @change="handleFileChange" />
  <p>{{ errorMessage }}</p>
</div>
</template>

全体は上記のようになります。

確認

csvを選択した時、2000KBを超えるサイズの画像を選択した時それぞれエラーメッセージが表示されました。


Discussion