Vue フォーム入力
本セクションでは、Vueにおけるフォーム入力(Form Inputs)の具体的な実装例を網羅的に解説します。これまでに学んだ v-model ディレクティブを活用し、ラジオボタン、チェックボックス、ドロップダウンリスト、そして標準的なテキスト入力フィールドをどのように制御するかを詳しく見ていきましょう。
1. ラジオボタン (Radio Buttons)
同じ選択グループに属するラジオボタンには、必ず同じ name 属性を指定し、一度に1つのボタンのみを選択できるようにします。
Vueでは他の入力要素と同様に v-model を使って入力をキャプチャしますが、<input type="radio"> タグには明示的に value 属性を設定する必要があります。
1.1 実装例
App.vue:
<template>
<h1>Vueにおけるラジオボタン</h1>
<form @submit.prevent="registerAnswer">
<p>一番好きな動物は何ですか?</p>
<label>
<input type="radio" name="favAnimal" v-model="inpVal" value="猫"> 猫
</label>
<label>
<input type="radio" name="favAnimal" v-model="inpVal" value="犬"> 犬
</label>
<label>
<input type="radio" name="favAnimal" v-model="inpVal" value="カメ"> カメ
</label>
<label>
<input type="radio" name="favAnimal" v-model="inpVal" value="ヘラジカ"> ヘラジカ
</label>
<button type="submit">送信</button>
</form>
<div>
<h3>送信された選択内容:</h3>
<p id="pAnswer">{{ inpValSubmitted }}</p>
</div>
</template>
<script>
export default {
data() {
return {
inpVal: '',
inpValSubmitted: 'まだ送信されていません'
}
},
methods: {
registerAnswer() {
if(this.inpVal) {
this.inpValSubmitted = this.inpVal;
}
}
}
}
</script>
<style scoped>
div {
border: dashed black 1px;
border-radius: 10px;
padding: 0 20px 20px 20px;
margin-top: 20px;
display: inline-block;
}
button {
margin: 10px;
}
label {
display: block;
width: 120px;
padding: 5px;
}
label:hover {
cursor: pointer;
background-color: rgb(211, 244, 211);
border-radius: 5px;
}
#pAnswer {
background-color: lightgreen;
padding: 5px;
}
</style>2. チェックボックス (Checkboxes)
チェックボックス入力(<input type="checkbox">)が v-model を通じて同じ配列に接続されている場合、チェックされた項目の値がその配列内に収集されます。
2.1 実装例
App.vue:
<template>
<h1>Vueにおけるチェックボックス入力</h1>
<form @submit.prevent="registerAnswer">
<p>どの種類の食べ物が好きですか?</p>
<label>
<input type="checkbox" v-model="likeFoods" value="ピザ"> ピザ
</label>
<label>
<input type="checkbox" v-model="likeFoods" value="ライス"> ライス
</label>
<label>
<input type="checkbox" v-model="likeFoods" value="魚"> 魚
</label>
<label>
<input type="checkbox" v-model="likeFoods" value="サラダ"> サラダ
</label>
<button type="submit">送信</button>
</form>
<div>
<h3>送信された回答:</h3>
<p id="pAnswer">{{ inpValSubmitted }}</p>
</div>
</template>
<script>
export default {
data() {
return {
likeFoods: [],
inpValSubmitted: 'まだ送信されていません'
}
},
methods: {
registerAnswer() {
this.inpValSubmitted = this.likeFoods;
}
}
}
</script>
<style scoped>
/* スタイルはラジオボタンの例と同様 */
div {
border: dashed black 1px;
border-radius: 10px;
padding: 0 20px 20px 20px;
margin-top: 20px;
display: inline-block;
}
label {
display: block;
width: 100px;
padding: 5px;
}
#pAnswer {
background-color: lightgreen;
padding: 5px;
}
</style>3. ドロップダウンリスト (Drop-down List)
ドロップダウンリストは、<select> タグとその内部の <option> タグで構成されます。
Vueでドロップダウンリストを使用する場合、<select> タグを v-model に接続し、各 <option> タグに値を付与します。
3.1 実装例
App.vue:
<template>
<h1>Vueにおけるドロップダウンリスト</h1>
<form @submit.prevent="registerAnswer">
<label for="cars">車を選択してください:</label>
<select v-model="carSelected" id="cars">
<option disabled value="">選択してください</option>
<option>ボルボ</option>
<option>サーブ</option>
<option>オペル</option>
<option>アウディ</option>
</select>
<br><br>
<input type="submit" value="送信">
</form>
<div>
<h3>送信された回答:</h3>
<p id="pAnswer">{{ inpValSubmitted }}</p>
</div>
</template>
<script>
export default {
data() {
return {
carSelected: '',
inpValSubmitted: 'まだ送信されていません'
}
},
methods: {
registerAnswer() {
if(this.carSelected) {
this.inpValSubmitted = this.carSelected;
}
}
}
}
</script>3.2 複数選択可能なドロップダウン ()
<select> タグに multiple 属性を追加すると、リストが展開され、複数のオプションを選択できるようになります。
Windowsユーザーは「Ctrl」キー、macOSユーザーは「Command」キーを押しながらクリックすることで複数選択が可能です。
App.vue:
<template>
<h1>Vueにおける複数選択</h1>
<p>OSに応じて「Ctrl」または「Command」キーを使用して、複数のオプションを選択してください。</p>
<form @submit.prevent="registerAnswer">
<label for="cars">1つ以上の車を選択してください:</label><br>
<select v-model="carsSelected" id="cars" multiple>
<option>ボルボ</option>
<option>サーブ</option>
<option>オペル</option>
<option>アウディ</option>
<option>起亜</option>
</select>
<button type="submit">送信</button>
</form>
<div>
<h3>送信された回答:</h3>
<p id="pAnswer">{{ inpValSubmitted }}</p>
</div>
</template>
<script>
export default {
data() {
return {
carsSelected: [],
inpValSubmitted: 'まだ送信されていません'
}
},
methods: {
registerAnswer() {
if(this.carsSelected.length > 0) {
this.inpValSubmitted = this.carsSelected;
}
}
}
}
</script>4. 読み取り専用のフォーム入力
フォーム入力に v-model を使用すると「双方向データバインディング(Two-way Binding)」が作成されます。これは、Vueインスタンスのデータが変更されると、入力の value 属性も同期して変更されることを意味します。
しかし、<input type="file"> のような読み取り専用の入力要素は、セキュリティ上の理由からJavaScript(Vueのデータインスタンス)から value 属性を書き換えることができません。そのため、v-model を直接使用することは不可能です。
このような場合は、@change イベントを使用してVueインスタンスのデータを更新するメソッドを呼び出す必要があります。
4.1 実装例(ファイル入力)
App.vue:
<template>
<h1>input type="file" の実装</h1>
<form @submit.prevent="registerAnswer">
<label>ファイルを選択:
<input @change="updateVal" type="file">
</label>
<button type="submit">送信</button>
</form>
<div>
<h3>送信された回答:</h3>
<p id="pAnswer">{{ inpValSubmitted }}</p>
</div>
</template>
<script>
export default {
data() {
return {
fileInp: null,
inpValSubmitted: 'まだ送信されていません'
}
},
methods: {
registerAnswer() {
if(this.fileInp) {
this.inpValSubmitted = this.fileInp;
}
},
updateVal(e) {
// イベントオブジェクトからファイルパスを取得
this.fileInp = e.target.value;
}
}
}
</script> 補足: 上記の例では、送信されたファイル名の前に C:\fakepath\ というパスが付与されます。これは、悪意のあるソフトウェアがユーザーの実際のファイル構造を推測するのを防ぐためのブラウザのセキュリティ仕様です。
5. その他のフォーム入力 (Other Form Inputs)
前述の入力要素では value 属性をプログラミング側で用意する必要がありましたが、以下の入力要素はユーザー自身が値を直接入力します。
<input type="color"><input type="date"><input type="datetime-local"><input type="number"><input type="password"><input type="range"><input type="search"><input type="tel"><input type="text"><input type="time"><textarea>
これらの要素を使用する場合、Vue側で行うべきことは v-model を使ってデータプロパティと接続するだけです。
5.1 レンジ入力 () の例
App.vue:
<form @submit.prevent="registerAnswer">
<label>あなたの身長は?<br>
<input v-model="heightInp" type="range" min="50" max="235"> {{ heightInp }} cm
</label>
<button type="submit">送信</button>
</form>5.2 カラーピッカー () の例
App.vue:
<form @submit.prevent="registerAnswer">
<label>色を選択してください:
<input v-model="colorInp" type="color">
</label>
<button type="submit">送信</button>
</form>5.3 テキストエリア () の例
App.vue:
<form @submit.prevent="registerAnswer">
<label>
<p>製品についてのご感想をお聞かせください:</p>
<textarea v-model="txtInp" placeholder="こちらに入力してください.." rows="4" cols="35"></textarea>
</label>
<button type="submit">送信</button>
</form>