くらげになりたい。

くらげのようにふわふわ生きたい日曜プログラマなブログ。趣味の備忘録です。

Nuxt+Buefy+VueValidate+TypeScript

Nuxt+Buefy+VueValidate+TypeScript

ひさびさにVeeValidateを見てみたら、
使いやすくなっていた気がするので、いろいろ調べたときの備忘録。

インストール

$ npm i vee-validate

tsconfig.json

メッセージファイルがjsonなので、
tsconfig.jsonに設定を追加。

{
  "compilerOptions": {
    "resolveJsonModule": true, // 追加
    "esModuleInterop": true, // 追加
    }
  }
}

Localization | VeeValidate

plugins/vue-validate.ts

VueValidateでは、バリデーションのルールは用意されているが、
設定しないと利用できない。
Available Rules | VeeValidate

なので、pluginsで初期設定する。

// plugins/vee-validate
import Vue from "vue";
import {
  ValidationProvider,
  ValidationObserver,
  extend,
  localize
} from "vee-validate";
import { required, email } from "vee-validate/dist/rules";
import ja from "vee-validate/dist/locale/ja.json";

// 利用するルールの設定
extend("required", required);
extend("email", email);

// メッセージの日本語化
localize("ja", ja);

// コンポーネントの登録
Vue.component("ValidationProvider", ValidationProvider);
Vue.component("ValidationObserver", ValidationObserver);

全ルールをインポートする場合は、こんな感じ。

import { extend } from 'vee-validate';
import * as rules from 'vee-validate/dist/rules';

// with typescript
for (let [rule, validation] of Object.entries(rules)) {
  extend(rule, {
    ...validation
  });
}

nuxt.config.tsの設定

作ったプラグインを反映。

// nuxt.config.ts
import { NuxtConfig } from "@nuxt/types";

const config: NuxtConfig = {
  plugins: [
    "~/plugins/vee-validate"
  ],
}
export default config;

使い方

全体はこんな感じ。

<template>
  <ValidationObserver ref="observer" v-slot="{ handleSubmit, valid }" slim>
    <form @submit.prevent="">
      <fieldset :disabled="loading">
        <ValidationProvider
          rules="required|email"
          name="メールアドレス"
          v-slot="{ errors, valid }"
          slim
        >
          <b-field
            label="メールアドレス"
            :type="{ 'is-danger': errors[0], 'is-success': valid }"
            :message="errors"
          >
            <b-input type="text" v-model="email" />
          </b-field>
        </ValidationProvider>

        <ValidationProvider
          rules="required"
          name="パスワード"
          v-slot="{ errors, valid }"
          slim
        >
          <b-field
            label="パスワード"
            :type="{ 'is-danger': errors[0], 'is-success': valid }"
            :message="errors"
          >
            <b-input type="password" v-model="password" />
          </b-field>
        </ValidationProvider>

        <b-field>
          <div class="control">
            <button
              type="submit"
              class="button is-primary"
              :class="{ 'is-loading': loading }"
              :disabled="!valid"
              @click="handleSubmit(submit)"
            >
              ログイン
            </button>
          </div>
        </b-field>
      </fieldset>
    </form>
  </ValidationObserver>
</template>

<script lang="ts">
import { Component, Vue, Prop } from "nuxt-property-decorator";

@Component
export default class LoginForm extends Vue {
  private loading: boolean = false;

  private email: string = "";
  private password: string = "";

  private submit() {
    if (!!this.loading) return;

    const data = {
      email: this.email,
      password: this.password,
    };
    this.$emit("submit", data);
  }
}
</script>
1. Form全体をValidationObserverで囲む
<ValidationObserver ref="observer" v-slot="{ handleSubmit, valid }" slim>
  <form @submit.prevent="">
    <fieldset :disabled="loading">
      <!-- 略 -->

      <b-field class="mt-5">
        <div class="control is-expanded">
          <button
            type="submit"
            class="button is-primary"
            :class="{ 'is-loading': loading }"
            :disabled="!valid"
            @click="handleSubmit(submit)"
          >
            ログイン
          </button>
        </div>
      </b-field>
    </fieldset>
  </form>
</ValidationObserver>

ポイントは以下の2つ

  • submitで実行したい関数を、handleSubmitでラップ
    • validなときにしか呼び出されない
  • バリデーションの結果は、validで渡される

Validation Observer | VeeValidate

2. 各フィールドをValidationProviderで囲む

各項目のバリデーションは、ValidationProviderで設定する。

<ValidationProvider
    rules="required|email"
    name="メールアドレス"
    v-slot="{ errors, valid }"
    slim
  >
  <b-field
    label="メールアドレス"
    :type="{ 'is-danger': errors[0], 'is-success': valid }"
    :message="errors"
  >
    <b-input type="text" v-model="email" />
  </b-field>
</ValidationProvider>
  • バリデーションルールは、ValidationProviderrulesに設定
    • 今回は必須とEmail形式
  • ValidationProvidernameに、項目名を設定できる
    • 「メールアドレスは必須入力です」みたいに使われる
  • errorsには、エラーになったルールのメッセージが入ってる
  • validは、エラーがないとtrue

slimをつけると、<span>で囲われなくなる

デフォルトでは、<ValidationObserver><ValidationProvider>は、<span>に置き換えられる。

Buefyの場合だと、cssが効かなくなってしまうので、あまりうれしくない。。

直接、slotの要素だけを描画して欲しいときは、slimオプションをつければOK。
Validation Provider | VeeValidate
Validation Observer | VeeValidate

ただ、Vue2の制約で<template>のルートは1つなので、 こんな感じになっているとNG。

<template>
  <ValidationObserver slim>
    <form />
    <form />
  </ValidationObserver>
</template>

ちゃんと一つの要素だけになるようにしないといけない。

<template>
  <ValidationObserver slim>
    <form />
  </ValidationObserver>
</template>

以上!!

参考にしたサイト様