Vue.js フォーム要素に対する v-model データバインディングの実装手法

テキストおよび数値入力フィールド

標準的なテキスト入力、パスワードフィールド、マルチラインテキストエリアでは、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>

タグ: vuejs v-model input-modifiers data-binding html-form-controls

10月12日 03:15 投稿