4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Vue.jsでHTML5標準のフォームバリデータを使う

Last updated at Posted at 2021-05-19

Vueでバリデーションというと、まず挙がるのはVeeValidateかと思います。
ある仕事でNuxt.jsを使う現場にアサインされた時も、バリデーターはVeeValidateが採用されてました。
でもあれ、記述が重いんですよね…。
どっちにしろバックエンドでバリデーションしますし。

趣味のサイトで、あそこまで高機能じゃなくていいからもうちょい楽にバリデーションできないかなぁと考えて思い出したのがHTML5標準のフォームバリデータ。
挙動はブラウザ依存にはなってしまいますが、例えばrequiredタグを付けるだけで、IE以外はバルーン表示でユーザに告知してくれます。必要十分で、楽です。

素のJavaScriptによるHTML5フォームバリデータ例

MDNでは「JavaScript無しの素のHTMLフォームでもバリデーション可能です」という紹介のされ方ですが、JavaScriptからDOM操作で該当のイベントを起動することが出来ます。

See the Pen HTML5 フォームバリデーション 素JavaScript実装例 by belgh (@belgh) on CodePen.

チェックボタンを押すと、HTMLのinputタグの属性に従ってバリデーションが行われるのが確認できると思います。
(本サンプルでは、:valid、:invalidで自動適用されるclassも設定しています)
JavaScript側ではイベント起動してるだけで、他は何もしていません。

上記のチェック例はrequired minlength="10"です。
他にemailやtel、dateなどのinput typeによるバリデーションや、pattern属性で正規表現を使うことも出来ます。

また、後述する方法で独自のバリデーションを実装することも出来ます。
(あまり複雑になるようだと、モジュール使ったほうがいいような気もしますが…)

Vue3(TypeScript)での実装例

ポイントはrefを使うこと。
TypeScriptの場合はHTMLInputElement型を明示します。
それだけです。

<script setup lang="ts">
import { ref } from 'vue'

// props略

const form = ref<HTMLInputElement | null>(null)
const validate = () => {
  if (form.value?.checkValidity() == false) {
    form.value.reportValidity()
    return false
  }
  return true
}
const create = () => {
  if (!validate()) {
    return false
  }
  // 以下略
}
</script>

<template>
  <form ref="form">
    <input :model="params.name" type="text" required minlength="10">
    <button type="button" @click="create">
      登録
    </button>
  </form>
</template>

エラーの表現方法はバルーンで固定されてしまいますが、

  • template部分のルール記載がものすごくシンプル
  • バリデーションのトリガイベントを書くだけで、実際のバリデーションとエラー告知はブラウザ任せ

であることが利点です。
楽でいいですよね。

独自のバリデーションを実装する

これに手を出すくらいなら有り物のモジュールに乗っかったほうがいいのでは…?
という意味であまり使う機会はないかもしれませんが、
独自のバリデーション実装も可能です。

以下は、標準では行えない「添付ファイルのサイズ」をチェックする例です。

<script>
const catchFile = (e: Event) => {
  if (e.target instanceof HTMLInputElement) {
    // checkValidityはエラーメッセージの有無に依存するので、必ずクリアする
    e.target.setCustomValidity('')
    if (e.target.files) {
      const image = e.target.files.item(0);
      if (image.size > 1024 * 1024 * 5) {
        // エラーメッセージを設定すると、checkValidityがfalseになる
        e.target.setCustomValidity(
          'ファイルサイズは5MB以下にしてください。'
        )
      }
    }
  }
}
</script>

<template>
  <input @change="catchFile" type="file" required>
</template>

これくらいなら許容範囲かな?と思います。
おわり。

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?