Things of interesting

プログラミングに関する技術ネタの備忘録

【Vue.js】Buefyでvuelidateを使ってバリデーション

やること

Vueのアプリ開発にBuefyというBulmaベースのライブラリを使おうかと考えていますが、 フォームごとや複雑なバリデーションを想定するとデフォルト機能のバリデーションだと心もとないなので Vuelidateというバリデーション用のライブラリと組み合わせて使ってみます。

事前準備

vue-cli 3.0 の環境で作りました。

vue create my-app

Buefyのインストール

yarn add buefy

Vuelidateのインストール

yarn add vuelidate

main.js

import Vue from 'vue';
import Buefy from 'buefy';
import 'buefy/dist/buefy.css';
import Vuelidate from 'vuelidate';

Vue.use(Buefy);
Vue.use(Vuelidate);

バリデーションを掛けるフォーム画面の作成

ログインページの想定で作ってみます。 (全量は下にあります。パスワードコンポーネントはbuefyデフォルトのものになっています)

Buefyのb-inputタグのカスタマイズ

ここでは必須(required)属性をサンプルとして実装してみます。

  • デフォルトのバリデーション属性は使わないので、requiredは外します。
  • 代わりに@blurblur時のイベント発火(vuelidateのバリデーション起動)をセットします。
  • b-fieldにはvuelidateのerror条件判定でtype,messageが表示されるように設定します。
  • スクリプトの方はloginIdのバリデーション定義をいれています。
  • vue-property-decoratorというライブラリを使っているのでそのまま使う場合はyarn等でインストールしてください。
            <b-field 
              :type="$v.loginId.$error ? 'is-danger': ''" 
              :message="$v.loginId.$error ? 'this is validation message' : ''" 
            >
              <b-input
                ref="loginId"
                v-model="loginId"
                placeholder="ログインID"
                @blur="$v.loginId.$touch"
              />
            </b-field>
〜省略〜
<script>
import { Component, Vue } from 'vue-property-decorator';
import { validationMixin } from 'vuelidate';
import { required, maxLength } from 'vuelidate/lib/validators';

@Component({
  mixins: [validationMixin],
  validations: {
    loginId: { required, minLength: maxLength(30) },
    password: { required, minLength: maxLength(30) }
  }
})
export default class Login extends Vue {
  loginId = '';
  password = '';

  error = false;
〜省略〜

まとめ

こんな感じでVuelidateと連携できるはずです!
Vuelidateだとthis.$v.$touch()を使ってのフォーム全体のバリデーション発火やthis.$v.$errorでの状態チェックが便利ですね!

Login.vue

<template>
  <section class="hero is-fullheight is-primary is-bold">
    <div class="hero-body">
      <div class="container has-text-centered">
        <h1 class="title">TITLE</h1>
        <p class="subtitle">SUB</p>
        <div class="column is-4 is-offset-4">
          <div class="box">
            <b-field 
              :type="$v.loginId.$error ? 'is-danger': ''" 
              :message="$v.loginId.$error ? 'this is validation message' : ''" 
            >
              <b-input
                ref="loginId"
                v-model="loginId"
                placeholder="ログインID"
                maxlength="30"
                @blur="$v.loginId.$touch"
              />
            </b-field>
            <b-field>
              <b-input
                ref="password"
                v-model="password"
                placeholder="パスワード"
                required
                type="password"
                maxlength="30" 
                password-reveal/>
            </b-field>
            <a
              :class="{ 'is-loading': loading }"
              class="button is-fullwidth is-primary"
              type="submit"
              @click="hoge()">LOGIN</a>
          </div>
        </div>
      </div>
    </div>
  </section>
</template>

<script>
import { Component, Vue } from 'vue-property-decorator';
import { validationMixin } from 'vuelidate';
import { required, maxLength } from 'vuelidate/lib/validators';

@Component({
  mixins: [validationMixin],
  validations: {
    loginId: { required, minLength: maxLength(30) },
    password: { required, minLength: maxLength(30) }
  }
})
export default class Login extends Vue {
  loginId = '';
  password = '';

  error = false;
  loading = false;

  hoge() {
    this.$v.$touch();
  }
}
</script>