VeeValidateでこれだけあれば大体のフォームに対応できそうだ！と思われる書き方

VeeValidateの4系でこれだけあれば大体のフォームに対応できそうなものを書いておきます。
かなりできることが多いのでこのやり方以外にもありそうですが、英語マニュアルが大変なので一旦下記にまとめます☺
## template
エラーの制御としては大まかにこんな感じです。
- ①各入力フィールドのチェック（正規表現などなど）
- ②CGI、Pythonなどのサーバーサイドでのチェック（本件ではメールアドレスの重複チェック）
- ③1つでもエラーが発生した場合の表示
- ④確認画面に遷移してからのエラーバック対応


```javascript:template
<template>
  <main>
    <article>
      <Form @submit="onSubmit" :initial-errors="errInitObj" v-slot="{ errors }">
        <section>
          <div>
            <dl>
              <p v-if="errInitObj.isError" class="error">※入力に不備がございます。内容をご確認ください</p>
              <div>
                <dt><i class="req">必須</i>お名前</dt>
                <dd>
                  <Field name="name" v-model="formObj.name" type="text" class="input_text" :rules="validateName" />
                  <ErrorMessage name="name" class="error" as="p" />
                </dd>
              </div>
                <dt><i class="req">必須</i>メールアドレス </dt>
                <dd>
                  <Field name="email" v-model="formObj.email" type="email" class="input_text"
                    :rules="validateEmail" />
                  <ErrorMessage name="email" class="error" as="p" />
                </dd>
              </div>
            <div class="btn_box" v-if="Object.keys(errors).length">
              <p class="error">
                必要な情報が入力されていません。再度ご確認ください。
              </p>
            </div>
            <div><button class="btn">確認画面へ</button></div>
          </div>
        </section>
      </Form>
    </article>
  </main>
</template>
```

## ①各入力フィールドのチェック
```javascript:template
<div>
  <dt><i class="req">必須</i>お名前</dt>
  <dd>
    <Field name="name" v-model="formObj.name" type="text" class="input_text02" :rules="validateName" />
    <ErrorMessage name="name" class="form_error" as="p" />
  </dd>
</div>

```
`:rules="validateName"`
バリデーションチェックは関数化できちゃいます。

`v-model="formObj.name"`
入力値を復元する時に使用します。(setFieldValueでいけちゃうかもー)

`<ErrorMessage name="name" class="form_error" as="p" />`
エラーを表示します。nameの値を合わせてください。

```javascript:script
function validateName(val) {
  if (!val) {
    return '正しく入力してください';
  }
  const regex = /.+?(\x20|\u3000).*?[^\x20|\u3000]/;
  if (!regex.test(val)) {
    return '姓と名の間にスペース(半角/全角)を入力してください';
  }
  return true;
}
```

## ②CGI、Pythonなどのサーバーサイドでのチェック
```javascript:template
<Form @submit="onSubmit" :initial-errors="errInitObj" v-slot="{ errors }">
```

`@submit="onSubmit"`
バリデーションチェックが全て問題なければ上記でonSubmit関数を実行し、ajaxでサーバー側でのバリデーションチェックを開始します。
`:initial-errors="errInitObj" v-slot="{ errors }"`
は、ここでは割愛。

```javascript:script
async function onSubmit(values, actions) {
  //console.log(JSON.stringify(values, null, 2));

  // メールアドレス重複チェック
  const params = {
    email: values.email,
  };
  // サーバー側と通信
  const json = await getJson(params);

  // all good
  if (!json.errorObj.isError) {
    // 保存して確認画面に遷移する的な処理は省略
    return;
  }
  // set single field error
  if (json.errorObj.email) {
    // <ErrorMessage name="email" class="form_error" as="p" /> にエラーセット
    actions.setFieldError('email', json.errorObj.email);
  }
}
```

## ③1つでもエラーが発生した場合の表示
```javascript:template
<Form @submit="onSubmit" :initial-errors="errInitObj" v-slot="{ errors }">

------略------

<div class="btn_box" v-if="Object.keys(errors).length">
  <p class="error _02">
    必要な情報が入力されていません。再度ご確認ください。
  </p>
</div>
```
`v-slot="{ errors }"`
エラーが発生すると、errosにオブジェクトとして蓄積されるので、
`Object.keys(errors).length`
を条件としてエラーを表示します。

## ④確認画面に遷移してからのエラーバック対応
全てのバリデーションチェックをパスして、最後の登録直前でサーバーサイドエラーが発生した場合などに有効です。
`:initial-errors="errInitObj"`
で初期エラーを表示できます。

```javascript:template
<Form @submit="onSubmit" :initial-errors="errInitObj" v-slot="{ errors }">

------略------

<p v-if="errInitObj.isError" class="error _02">※入力に不備がございます。内容をご確認ください</p>
```
```javascript:script
const errInitObj = reactive(storeObj.$state.errInitObj)
```
今回は[Pinia](https://pinia.vuejs.org/)を使用しているのでerrInitObjは下記で保存して値を渡しています。
```javascript:script（確認画面）
const json = await getJson(params)
// エラー発生
if (json.errorObj.isError) {
  storeObj.errorObjWrite(json.errInitObj)
  router.push({
    name: "form",
  });
}
```
```javascript:Pinia
export const useStoreRegistry = defineStore('registry', {
  state: () => ({
    errInitObj: {
      isError: '',
      name: '',
      email: '',
    },
  }),
  actions: {
    errorObjWrite(errInitObj) {
      this.errInitObj = errInitObj;
    },
  },
});
```