vue.jsでアプリケーションを構築する時に入力フォームを設置する場合はvue.jsを使って入力フォームの要素を制御する必要があります。要素によって設定方法が異なるので、使いこなせるようにしっかりと理解しておきましょう。

Vue3からはコードの記述方法が2つ存在します。Vue2までの記述方法と同じOptions APIとVue3から新たに利用できるComposition APIです。両方の方法で設定方法を確認していくので記述方法の違いも同時に理解することができます。

入力フォームの使い方がわかったらinput要素やselect要素のコンポーネント化をすることをおすすめします。一度それらの要素をコンポーネント化するとプロジェクトを超えて再利用することができるのでフォームのデザインを統一することができます。

v-modelディレクティブ

入力フォームとvue.jsの管理下にあるデータプロパティを結びつけるためにv-modelディレクティブを利用します。v-modelを利用することでinput要素、textarea要素、select要素に入力した値をvue.jsで定義したデータに反映させることができます。またvue.jsのデータを更新することでinput要素に表示されている文字列も更新することができます。本文書では各要素でのv-modelの使用方法を確認しながら理解を深めていきます。

vue.jsではv-を接頭語にしたディレクティブという特別な属性が多数存在します。vue.jsはそのディレクティブを識別してどのような動作を行うか判断します。入力フォームの値とvue.jsのデータを結びつける場合はv-modelを利用します。

テキストボックスの場合

テキストボックスでv-modelディレクティブを使用する場合は下記のように記述します。


<input type="text" v-model="プロパティ名">

実際にテキストボックスを使って動作確認を行います。プロパティ名をtextInputとしてinput要素をhtml文の中に追加します。


<div id="app">
    <input type="text" v-model="textInput">
</div>

【composition APIの場合】

ref関数をimportしてtextInput変数を定義します。ref関数の引数には初期値を設定することができます。初期値には”(ブランク)としています。


<script setup>
import { ref } from 'vue';

const textInput = ref('');
</script>	

【options APIの場合】

vue.jsのdataの中にtextInputプロパティを追加し、初期値は”(ブランク)としています。


var app = new Vue({
  el: '#app',
  data: {
  	textInput: '',		
  }
})	

画面上には、input要素によるテキストボックスの入力エリアが表示されます。この状態ではテキストボックスに何か文字列を入力してもテキストボックスに入力した文字が表示されるだけでそれ以外は何も変化がありません。

input テキスト入力フォーム
input テキスト入力フォーム

次に入力した内容を見るためにはvue.jsのデータプロパティであるtextInputプロパティを画面に表示させます。{{ textInput }}を使ってhtmlの中に埋め込みます。


<div id="app">
    <input type="text" v-model="textInput">
    <p>{{ textInput }}</p>
</div>

テキストボックスに文字列を打ち込むと入力した内容がそのままテキストボックスの下に表示されます。このようにv-modelを使用することで入力したデータが即座にvue.jsのdataのtextInputに反映され、そのデータがブラウザ上に表示されることがわかります。

inputフォームの下に表示
inputフォームの下に表示

通常のテキストボックスの場合はvalue属性に値(<input text=”type” value=”初期値”>)を設定するとその値がテキストボックスに入った状態で表示されます。しかし、v-modelを使っている場合はvalue値を事前に入力してもvalueに設定した値はブラウザには表示されません。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const textInput = ref('初期値はここに入れておく');
</script>

【options APIの場合】

初期値を入れるためには、属性値のvalueではなくdataのtextInputの値を設定しておく必要があります。


var app = new Vue({
  el: '#app',
  data: {
  	textInput: '初期値はここに入れておく',		
  }
})	

ブラウザで確認すると初期値が入力された状態で表示されます。

初期値を入力
初期値を入力

v-modelを使った記述方法をsyntax sugar(糖衣構文)といい、書き方をシンプルでわかりやすくしています。実際はv-bindと@inputを使って以下のように記述することが可能です。


<input :value="textInput" @input="textInput = $event.target.value" />

少し上級者向けの内容になるかもしれませんが、syntax sugarについては下記の文書でも説明を行っています。

双方向バインディングとは

テキストボックスのv-modelの使い方が理解できたと思いますので、用語の確認を行なっておきます。

v-modelの説明を調べていくと双方向バインディングやTwo wayバインディングという用語をよく目にします。それらがどういう意味なのか確認していきましょう。

バインディングやバインド?

バインディング(binding)とバインド(bind)は英語ではどちらも同じ意味で何かと何かを結びつけることを意味します。

composition APIの場合

composition APIではref関数またはreactive関数を利用して変数を定義し、htmlの要素(下記ではp要素)にv-textを設定することで定義した変数の値をhtmlの要素の中に表示させることができます。このようにVueで定義した変数と要素が結びついているのでバインドまたはバインディングといいます。


<script setup>
import { ref } from 'vue';

const textInput = ref('バインディングとは');
</script>

<template>
  <p v-text="textInput"></p>
</template>

options APIの場合

options APIではdataプロパティを設定し、htmlの要素(下記ではp要素)にv-textを設定することでdataプロパティの値をhtmlの要素の中に表示させることができます。このようにdataプロパティと要素が結びついているのでバインドまたはバインディングといいます。


<div id="app">
	<p v-text="textInput"></p>
</div>


<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
var app = new Vue({
  el: '#app',
  data: {
  	textInput: 'バインディングとは',		
  }
})

双方向(two way)バインディング

options APIのコードを利用して双方向バインディングを説明しています。

双方向(Two Way)ということは2方向のバインディングが存在することを表しています。

v-textでは1方向のバインドでしたが、v-modelになると双方向のバインドになります。

一つ目の方向は、Vueインスタンスの中で設定したdataプロパティの値がinput要素と結びついてブラウザ上に表示されるバインドで、もう一つの方向はinput要素に入力した値がVueインスンスのdataプロパティの値に反映されるバインドです。このように2つの方向を持っているので双方向(two way)バインディングと呼ばれます。

双方向バインディング
双方向バインディング

先ほど出てきたv-modelの別の記述方法を確認することで双方向バインディングはより明確になります。v-bindディレクティブによりtextInputに設定した値がテキストブロックに表示され、v-onディレクティブによりテキストブロックに入力した値がtextInputに反映されます。


<input :value="textInput" @input="textInput = $event.target.value" />

テキストエリアの場合

テキストボックスでは改行を行うことができないので長い文章を入力することができません。改行が必要な長い文章を入力する場合はテキストエリアtextarea要素を使用します。テキストエリアでv-modelディレクティブを使用する場合は下記のように記述します。テキストエリアで入力した値が設定したプロパティに保存されます。


<textarea v-model="プロパティ名"></textarea>

テキストエリアなので値はtextareaタグの中に入れてしまいそうですが、下記のように記述しても双方向ではないので中身を更新してもvue.jsのdataプロパティには値の反映は行われません。


<textarea>{{ textInput }}</textarea>

チェックボックスの場合

1つのチェックボックスの場合

v-modelを使用したチェックボックスの書式は下記となります。


<input type="checkbox" v-model="プロパティ名">

checkboxのプロパティはtrue, falseの真偽値のみ設定することが可能です。

チェックボックスを準備してプロパティはcheckValueとします。現在の設定値がわかるように{{ checkValue }}を使って値も表示させます。


<div id="app">
	<input type="checkbox" v-model="checkValue">
	<p>{{ checkValue }}</p>
</div>

チェックボックスではプロパティは真偽値をとるので、初期値はtrueとします。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const checkValue = ref(true);
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	checkValue: true,		
  }
})
</script>

ブラウザで確認すると下記のように表示されます。初期値がtrueなので、ボックスが選択された形で表示されます。

チェックボックスの値をtrue
チェックボックスの値をtrue

チェックを外すと値はtrueからfalseに変わります。

チェックを外した場合
チェックを外した場合

true、falseしかとれないと説明しましたが、true-value、false-valueという属性を利用するとtrue, false以外の値をとることができます。

下記ではtrue-valueとfalse-valueを使用して”はい”と”いいえ”になるように変更を行なっています。


<div id="app">
	<input type="checkbox" v-model="checkValue" true-value="はい" false-value="いいえ">
	<p>{{ checkValue }}</p>
</div>

checkValueプロパティの初期値は”はい”とします。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const checkValue = ref('はい');
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	checkValue: 'はい',		
  }
})
</script>

初期値が”はい”になっているので、チェックした状態で値は”はい”となります。

checkboxをチェックした状態
checkboxをチェックした状態

チェックを外すと”いいえ”となります。

checkboxを外した場合
checkboxを外した場合

このようにtrue-value, false-valueを設定することでtrue, falseの真偽値から任意の値を取れるようになることが確認できました。

複数のチェックボックスの場合

複数のチェックボックスを利用する場合の書式は下記の通りです。


<input type="checkbox" v-model="プロパティ名" value="値1">
<input type="checkbox" v-model="プロパティ名" value="値2">
<input type="checkbox" v-model="プロパティ名" value="値3">

1つのチェックボックスではデフォルトでは真偽値のtrue, falseの2つをとることができますが、複数のチェックボックスの場合は、各チェックボックスで設定したvalueの値を配列で取得します。

実際に確認してみましょう。

同じグループの場合は、v-modelには同じプロパティを設定し、valueにはそのチェックボックスが選択された時の値を設定します。checkValueプロパティの値をブラウザに表示できるように{{ checkValue }}も追加します。


<div id="app">
	<input type="checkbox" v-model="checkValue" value="ラグビー"> ラグビー
	<input type="checkbox" v-model="checkValue" value="サッカー"> サッカー
	<input type="checkbox" v-model="checkValue" value="バスケットボール"> バスケットボール
	<p>{{ checkValue }}</p>
</div>

checkValueは配列なので、初期値は空の配列を設定します。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const checkValue = ref([]);
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	checkValue: [],		
  }
})
</script>

デフォルトは何も選択していない状態なので、下記のようになります。

何も選択していない状態
何も選択していない状態

サッカーのみを選択すると配列にサッカーが入ることがわかります。

サッカーのみ選択
サッカーのみ選択

サッカーの次にバスケットボール、ラグビーと選択すると選択した順に値は配列に入っていくことがわかります。

すべてをチェックした状態
すべてをチェックした状態

このように複数のチェックボックスでは各チェックボックスに設定した値が配列としてvue.jsのdataプロパティの中に保存されることがわかります。

初期値を設定しておきたい時は下記のようにcheckValueの配列に値を入れておきます。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const checkValue = ref(['サッカー']);
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	checkValue: ['サッカー'],		
  }
})
</script>

チェックボックスに選択肢にないものを入れることも可能ですが、チェックボックスの選択からの影響は受けず配列に入ったままの状態となります。

【composition APIの場合】


<script>
import { ref } from 'vue';

const checkValue = ref(['サッカー', '野球']);)
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	checkValue: ['サッカー','野球'],		
  }
})
</script>

チェックボックスに選択する値がなくても野球は配列には入った状態になります。

チェックボックスに影響を受けない値
チェックボックスに影響を受けない値

すべてのチェックボックスを外しても配列に残った状態となり、チェックボックスからの影響は全く受けません。

チェックボックスに影響を受けない
チェックボックスに影響を受けない

ラジオボタンの場合

ラジオボタンでは複数の選択肢から1つを選択させたい場合に利用します。複数のチェックボックスと設定方法はほとんど同じですが、ラジオボタンでは値は配列ではなく文字列として取得します。

ラジオボタンの書式は下記の通りです。


<input type="radio" v-model="プロパティ名" value="値1">
<input type="radio" v-model="プロパティ名" value="値2">
<input type="radio" v-model="プロパティ名" value="値3">

実際にラジオボタンを使って動作確認を行なってみましょう。

同じグループの場合は、v-modelには同じプロパティを設定し、valueにはそのラジオボタンが選択された時の値を設定します。radioValueプロパティの値をブラウザに表示できるように{{ radioValue }}も追加します。


<div id="app">
	<input type="radio" v-model="radioValue" value="ラグビー"> ラグビー
	<input type="radio" v-model="radioValue" value="サッカー"> サッカー
	<input type="radio" v-model="radioValue" value="バスケットボール"> バスケットボール
	<p>{{ radioValue }}</p>
</div>

radioValueは文字列なので、初期値は”(ブランク)を設定します。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const radioValue = ref('');	

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	radioValue: ''	
  }
})
</script>	

ラジオボタンを選択していない状態です。

ラジオボタンを選択していない状態
ラジオボタンを選択していない状態

ラジオボタンを選択すると選択した値が{{ radioValue}}に表示されます。

ラジオボタンを選択した状態
ラジオボタンを選択した状態

ラジオボタンは複数の選択を行うことができないので、別のボタンに変更すると別の選択した値がブラウザ上に表示されます。

セレクトボックスの場合

1つを選択する場合

プルダウンメニューを使って選択肢の中から1つだけ選択する場合のセレクトボックスの設定方法を確認します。1つだけ選択を行うので値は文字列として取得できます。

セレクトボックスの書式は下記の通りです。


<select v-model="selectValue">
	<option>値1</option>
	<option>値2</option>
	<option>値3</option>
</select>
<p>{{ selectValue }}</p>

実際にセレクトボックスを使って動作確認を行なってみましょう。

select要素にv-modelでselectValueプロパティを設定します。プルダウンメニューで選択した値はこのselectValueプロパティの値に入ります。selectValueの値は{{ selectValue }}でブラウザに表示されます。

下記のコードではoptionにdisabledが設定されていますが、disabledを設定した項目は選択することができません。ページを開いた直後はこの選択項目が表示されていますが一度選択を開始するとdisabledの項目を選択することができなくなります。

<div id="app">
	<select v-model="selectValue">
		<option disabled value="">興味のあるスポーツを選択</option>
		<option>ラグビー</option>
		<option>サッカー</option>
		<option>バスケットボール</option>
	</select>
	<p>{{ selectValue }}</p>
</div>

selectValueプロパティの値は文字列なので””(ブランク)を設定しています。

【composition APIの場合】


import { ref } from 'vue';

const selectValue = ref('');

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	selectValue: ''	
  }
})
</script>	

ページを開いた直後は、disabledの項目が表示されています。

プルダウンメニューで何も選択されていない状態
プルダウンメニューで何も選択されていない状態

プルダウンメニューで選択すると下記のように選択した値がブラウザに表示されます。

プルダウンメニューで選択
プルダウンメニューで選択

プルダウンメニューを選択している状態です。disabledに設定した項目は選択することができません。

プルダウンメニューを選択している状態
プルダウンメニューを選択している状態

selectValueにデフォルト値を選択するとプルダウンメニューで選択された状態で表示されます。

下記のようにdesign_usersがオブジェクトの場合ブラウザ上の選択では名前を表示させ、保存する値がidの場合は:value=”design_user.id”と設定することで名前ではなくidを保存することができます。


<select v-model="selectValue">
  <option 
    v-for="design_user in design_users" 
    :key="design_user.id" 
    :value="design_user.id"
  >
    {{ design_user.name }}
  </option>
</select>

複数を選択する場合

一つの選択の場合は、文字列で値を取得できましたが、複数の場合は配列で値を取得することができます。

複数を選択可能にするためには、select要素にmultipleを設定する必要があります。html部分の記述に関しては1つを選択する場合と複数を選択する場合の違いはmultipleを追加するかどうかの違いです。


<div id="app">
	<select v-model="selectValues" multiple="">
		<option>ラグビー</option>
		<option>サッカー</option>
		<option>バスケットボール</option>
	</select>
	<p>{{ selectValues }}</p>
</div>

値を複数選択することができるので、select_valuesプロパティの初期値は配列を設定します。

【composition APIの場合】


import { ref } from 'vue';

const selectValues = ref([]);

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data: {
  	selectValues: []
  }
})

selectにmultipleを設定するとプルダウンメニューではなく複数の要素を選択する画面になります。

select要素による複数選択画面
select要素による複数選択画面

複数選択を行うと選択した値が配列で表示されます。

複数要素を選択した画面
複数要素を選択した画面

ファイルの場合

HTMLの入力フォームではinput要素のtypeをfileに設定することでファイル情報を取得することができます。しかし、v-modelではファイルタイプを扱うことはできません。その代わり、changeイベントを利用してファイル情報を取得することができます。

これまではv-modelを使用していましたがファイルの場合はchangeイベントを利用します。changeイベントを設定しているので、ファイルの選択が行われれるとchangeイベントに設定されているhandleFileメソッドが実行されます。

changeイベントはv-onディレクティブを使用して設定を行います。

<div id="app">
	<input type="file" v-on:change="handleFile">
	{{ fileData }}
</div>

handleFileメソッドでeventからファイルの情報を取得してfileDataプロパティにその値を設定します。

【composition APIの場合】


<script setup>
import { ref } from 'vue';

const fileData = ref('');
const handleFile = (event) => {
  const file = event.target.files[0];
  fileData.value = file;
};
</script>

【options APIの場合】


<script>
var app = new Vue({
  el: '#app',
  data:{
  	fileData: ''
  },
  methods: {
  	handleFile: function(event){
  		file  = event.target.files[0]
  		this.fileData = file
  	}
  }
})
</script>	
ファイル選択画面
ファイル選択画面

ファイルを選択するとchangeイベントにより、filehandleメソッドが実行され、画面にはFileオブジェクトが表示されます。

ファイルを選択後の画面
ファイルを選択後の画面

Fileオブジェクトだけだとわかりにくいので、取得したファイル情報から名前を取得します。画面にはアップロードしたファイル名が表示されます。


//composition API
fileData.value = file.name;

//options API
this.fileData = file.name;

まとめ

入力フォームに必要な一つ一つの要素を確認していくとvue.jsでの設定がそれほど難しくないことが理解できたかと思います。ぜひ本文書の知識を生かしてVue.jsでの入力フォームの作成にチャレンジしてください。