【Vue.js】CompositionAPIでフォームを実装
はじめに
最近趣味で、Vue.js、CompositionAPIを試しています。
その一環として、フォームをできる限りライブラリを使わずに実装してみたので、記事に残したいと思います。
更新履歴
- 2021/06/29:
event.target
の参照方法を修正
フォームの概要
event.target
の参照方法を修正今回作成したフォームは、簡単な「ユーザー作成フォーム」です。
入力フィールドは「ユーザー名」と「メールアドレス」の2つです。
また、入力値に問題があれば、以下のようにエラーメッセージを表示します。
作成したソースコード
今回作成したソースコードは、以下のGithubリポジトリで公開しています。
入力フィールド / useField
動作
ユーザー作成フォームコンポーネントの実装の中で、まず入力フィールドから説明します。
入力フィールドは、input属性とエラーメッセージの2つからなります。
エラーメッセージは入力バリデーションがエラーの場合に表示されます。今回のバリデーションエラーの判定条件は「ユーザー名が空欄ではない」ことです。
しかし、入力フィールドの初期状態は空欄であるためエラー判定となります。ユーザーからすると、何も操作していないにも関わらずいきなりエラーメッセージを見せられるのは心象が良いとはいえません。
そのため、このフォームでは初期状態はバリデーションエラーとはせず、ユーザーが入力フィールドに操作が行われた後にエラー判定を始めるようにしました。具体的なエラー判定開始タイミングは、入力フィールドに対するfocusが外れたとき(Blur)です。
実装
以上を踏まえて、ここから実装について説明します。
まず、入力フィールドに関するロジックを定義したuseField
です。
// useField.ts
import { ref, computed } from 'vue';
const useField = (
initialValue: string,
validate: (value: string) => boolean = () => false
) => {
const value = ref(initialValue);
const isTouched = ref(false);
const error = computed(() => {
return !validate(value.value);
});
const onInput = (event: Event) => {
const { target } = event;
if (target instanceof HTMLInputElement) {
value.value = target.value;
}
};
const onBlur = () => {
isTouched.value = true;
};
return {
props: { value, onInput, onBlur },
meta: {
isTouched,
error,
},
};
};
export default useField;
useFiledは「入力フィールドの初期値」と「入力バリデーション判定式」の2つを渡すことで入力フィールドのロジックを返します。
useFieldが管理する状態は入力値(value)、ユーザーの入力フィールドの操作判定(isTouched)、バリデーションエラー判定(error)の3つです。これらはrefとcomputedを利用し、リアクティブな値として定義しています。
入力値のvalueはonInput関数によって値が更新されます。onInput関数は該当の入力フィールドの@input
に指定することで、入力値の変更をトリガーにonIput関数が発火しvalueが更新されます。
またisTouchedはonBlur関数によって値が更新されます。onBlurは該当の入力フィールドの@blur
に指定し、入力フィールドに対するfocusが外れたタイミングでisTouchedを更新します。
<!-- useFieldのロジック指定方法 -->
<input :value="value" @input="onInput" @blur="onBlur" />
また、useFieldの戻り値はprops
とmeta
という名前で構造化しました。props
については、該当の入力フィールドにinput
に指定する属性を集約しています。また、meta
はエラーといったいわゆるmeta情報を集めています。
useFieldを使ったForm実装
先ほど説明したuseFieldを使ってFormの入力フィールドを実装すると、以下のようなコードになります。
<!-- UserCreateForm.vue -->
<template>
<div class="field">
<label class="label" for="user-name">ユーザー名</label>
<div class="control">
<input
id="user-name"
name="user-name"
type="text"
:value="userNameField.props.value.value"
@input="userNameField.props.onInput"
@blur="userNameField.props.onBlur"
/>
<p
class="help is-danger"
v-show="
userNameField.meta.isTouched.value && userNameField.meta.error.value
"
>
ユーザー名を入力してください。
</p>
</div>
</div>
</template>
<script lang="ts">
import { createComponent } from '@vue/composition-api';
import useField from './useField';
export default createComponent({
setup() {
// ユーザー名フィールドの定義
const userNameField = useField('', (value: string) => {
return value.length > 0;
});
return { userNameField };
},
});
</script>
<script>
内でユーザー名のフィールド情報(userNameField
)を初期化します。そして目的のinput属性にフィールド情報を設定します。
また、エラーメッセージについてはInputにフォーカスが離れた後、バリデーションエラーの場合に表示されるように定義しました。
Submit処理の実装
まず、Formの<script>
部分のコードです。フォームで利用するSubmitメソッド(onSubmit
)とフォームエラー判定を定義します。
<script lang="ts">
import { defineComponent } from 'vue';
import useUserCreateForm from './composition';
export default defineComponent({
setup() {
// 各フィールドの定義(バリデーションメソッドの詳細は後述する)
const userNameField = useField('', presenceValidator);
const emailField = useField('', emailValidator);
// フォームのエラー判定。各フィールドにエラー情報を元に判定する。
const error = computed(() => {
return userNameField.meta.error.value || emailField.meta.error.value;
});
// submitメソッド。各フィールドの値を使い、サーバーにPOSTリクエストを送信する。
const onSubmit = async () => {
if (error.value) {
return;
}
// 今回はサーバーリクエストは行っていない
console.log(userNameField.props.value.value, emailField.props.value.value);
};
// 各フィールド情報とフォーム情報をtemplate層に渡す
return {
userNameField,
emailField,
onSubmit,
meta: {
error,
},
};
},
});
</script>
上述で利用した各フィールドのバリデーションメソッドは以下の通りです。
export const presenceValidator = (value: string) => {
return value.length > 0;
};
export const emailValidator = (value: string) => {
const re = /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/;
return re.test(value);
};
次にフォームの<template>
層の実装は以下の通りです。<script>
層で定義したonSubmit
を送信ボタンクリック時に実行されるように定義します。
また、フォーム全体のエラー判定を送信ボタンの:disabled
に指定することで、エラー時にボタンクリックができないようにします(disalbed状態)。
<template>
<div class="container">
<form @submit.prevent>
<!-- 各フィールドは省略 -->
<div class="field">
<p class="control">
<button
class="button is-success"
type="submit"
@click="onSubmit"
:disabled="meta.error.value"
>
作成する
</button>
</p>
</div>
</form>
</div>
</template>
終わりに
今回はVue.jsのComposition APIを使ったフォーム実装について説明しました。
今回の実装は、以下の2つのライブラリを参考にして実装しました。
自分が普段はReact & hooksでフロントエンドコードを書いているので、Reactライクなコーディングになっている気がします。
何はともあれ、読んだ方に少しでも参考になれば幸いです。
Author And Source
この問題について(【Vue.js】CompositionAPIでフォームを実装), 我々は、より多くの情報をここで見つけました https://qiita.com/Ushinji/items/b305e90b0848f5c0d698著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .