vue.jsでは入力フォーム内を構成する各要素をコンポーネント化し再利用することでアプリケーション内で統一したデザインの入力フォームを作成することができます。

入力フォーム内を構成する最小単位の1つとしてinput要素があります。最近ではAtomic Designを取り入れてアプリケーションを構築することもあり、input要素のコンポーネント化を方法を理解しておくことが非常に重要です。

v-modelディレクティブとは

input要素などの入力フォームの要素にv-modelディレクティブを設定することで要素に入力した値とVue.jsで定義したデータプロパティで双方向のデータバインディングが行われます。

データバインディングが行われるとinput要素で入力した値がそのままデータプロパティに設定されます。Vue.jsで入力フォームを作成している人にとっては見慣れた書式だと思います。


<input v-model="message" />

このv-modelですが実は下記のように書き換えることができます。$event.targetはinput要素そのものです。$event.target.valueによりinput要素に入力した値をvalueで取得しています。


<input v-bind:value="message" v-on:input="message = $event.target.value" />

v-modelを使った記述方法をsyntax sugar(糖衣構文)といい、書き方をシンプルにわかりやすくしています。

v-bindとv-onを短縮形にすると以下のようになります。


<input :value="message" @input="message = $event.target.value" />
v-modelから:valueと@inputを使って記述に変更しても動作が変わらないことを確認してください。

@inputはinput要素に文字を入力される度に発火されるイベントです。日本語の変換が確定していなくてもイベントは発火されます。文字を入力する度にevent.target.valueの値がmessageプロパティに設定されます。

また以下のように@inputイベントにメソッドを設定して値の設定を行っても処理の動作は変わりません。


<input :value="message" @input="inputValue" />
//略
        methods:{
            inputValue(){
                this.message = event.target.value;
            }
        }

v-modelのコンポーネントの作成

v-modelの本来の記述方法がわかりました。その記述を利用することでinput要素のコンポーネント化を行うことができます。

input要素のコンポーネントのTestInput.vueファイルを作成します。input要素をコンポーネント化する目的には”統一されたデザインの入力フォームの作成”があるのでclassを設定しています。それぞれのアプリケーションのデザインに合わせたclassを設定してください。input要素のデザインを変更したい場合はこのclassを設定することでこのコンポーネントを利用しているすべてのフォームで変更が反映されます。


<template>
    <input class="form-input rounded-md shadow-sm" :value="value" @input="$emit('input', $event.target.value)">
</template>

<script>
    export default {
        props: ['value'],
    }
</script>

TestInput.vueのコンポーネントは親コンポーネントからpropsでvalueを受け取り、input要素に入力した値は$emitを利用して親にデータを渡しています。$emitを利用して親のデータを渡すというのがポイントになります。

Vue.jsでは親コンポーネントから子にデータを渡したい場合はprops、子コンポーネントから親にデータを渡したい場合は$emitを利用します。

親側のコンポーネントでは@inputを利用して子コンポーネントからemitされたinputイベントを取得してその値をmessageプロパティに設定しています。


<text-input :value="message" @input="message = $event" />

上記の記述は下記のようにsyntax sugar(糖衣構文)であるv-modelを利用して記述することが可能です。


<text-input v-model="message" />

一度コンポーネントを作成すればinputタグからtext-inputタグに変更する必要はありますが、inputタグに対して個別にCSSを適用することなく統一したデザインの入力フォームを作成することができます。