テキストおよび数値入力フィールド
標準的なテキスト入力、パスワードフィールド、マルチラインテキストエリアでは、v-model ディレクティブを用いて DOM との状態を双方向に同期します。特定のユースケースに合わせて以下の修飾子をパラメータとして付与することで、入出力動作を制御できます。
.trim: ユーザーが入力した文字列の先頭と末尾に含まれる全角・半角スペースを自動で除去します。途中に含まれる空白はそのまま保持されます。.lazy: デフォルトでは毎回の入力操作(inputイベント)でバインディングを更新しますが、本修飾子を適用すると、入力コントロールからフォーカスが離れた時(changeイベント)のみデータを反映します。.number: 入力された値を可能な限り数値型へキャストします。解析不能な文字列が入力された場合は元の値が保持され、再計算時に再び数値型へ変換を試みます。
<input type="text" v-model.trim="formData.userName">
<input type="password" v-model="formData.userPass">
<textarea v-model.lazy="formData.memo"></textarea>
<input type="number" v-model.number="formData.years">
ラジオボタン グルーピング
排他的な選択肢を提供する場合、同一グループの要素には一致する"name"属性値を割り当てます。v-model は単一のプロパティに紐付けられ、選択された要素の"value"属性がモデルにセットされます。
<label><input type="radio" v-model="formData.category" name="optGroup" value="personal"> 個人用</label>
<label><input type="radio" v-model="formData.category" name="optGroup" value="business"> 法人用</label>
チェックボックスとセレクトリスト
シングル チェックボックス: value 属性を省略すると、v-model はブール値(true/false)の遷移を管理します。チェックボックスのオン・オフ状態が直接データ層へ反映されます。
<input type="checkbox" v-model="formData.acceptRules"> 利用規約に同意する
マルチプル チェックボックス: 複数選択を許容する場合は、v-model を配列型プロパティに設定し、各チェックボックスに個別の値属性を与えます。選択状態が変化すると、対応する値が配列へ追加または削除されます。
<input type="checkbox" v-model="formData.tags" value="前端"> 前端開発
<input type="checkbox" v-model="formData.tags" value="Node"> サーバーサイド
<input type="checkbox" v-model="formData.tags" value="DB"> データベース管理
セレクト リスト: <select> タグにも同様のバインディングを適用します。必須要件として、すべての
<select v-model="formData.zone">
<option value="">ゾーンを選択</option>
<option value="APNE">アジア太平洋東部</option>
<option value="USE">米国西部</option>
<option value="EUC">欧州中部</option>
</select>
統合コンポーネント サンプル
前述の入力制御を組み合わせた、送信ロジック付きの完全な構成例です。Options API ベースで状態管理とイベントハンドリングを実装しています。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<title>フォームデータ収集</title>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
</head>
<body>
<div id="app">
<form @submit.prevent="sendData">
<p>ログインID: <input type="text" v-model.trim="model.account"></p>
<p>パスワード: <input type="password" v-model="model.loginPass"></p>
<p>年齢: <input type="number" v-model.number="model.age"></p>
<p>性別:
<input type="radio" v-model="model.gender" name="gOpt" value="M"> 男性
<input type="radio" v-model="model.gender" name="gOpt" value="F"> 女性
</p>
<p>関心領域:
<input type="checkbox" v-model="model.interests" value="design"> UIデザイン
<input type="checkbox" v-model="model.interests" value="dev"> システム開発
<input type="checkbox" v-model="model.interests" value="data"> 分析作業
</p>
<p>{所属部署:
<select v-model="model.department">
<option value="">部署を選択</option>
<option value="sales">営業部</option>
<option value="eng">技術本部</option>
<option value="support">サポート課</option>
</select>
</p>
<p>自由コメント: <textarea v-model.lazy="model.note"></textarea></p>
<p><input type="checkbox" v-model="model.consent"> 個人情報取り扱い方針に同意</p>
<button type="submit">登録実行</button>
</form>
<div v-if="dumpJson">
<h3>ダンプ出力:</h3>
<pre>{{ dumpJson }}</pre>
</div>
</div>
<script>
const { createApp } = Vue;
createApp({
data() {
return {
dumpJson: null,
model: {
account: '',
loginPass: '',
age: null,
gender: 'M',
interests: [],
department: '',
note: '',
consent: false
}
};
},
methods: {
sendData() {
// 変更不能なスナップショットを取得して表示用データに代入
this.dumpJson = JSON.parse(JSON.stringify(this.model));
alert('処理が正常に終了しました');
console.log(this.dumpJson);
}
}
}).mount('#app');
</script>
</body>
</html>