[Vue入門] フォーム入力バインディング

フロントエンドでフォームを扱う場合、フォームの入力要素の状態と、対応する JavaScript の状態を同期しなければならないことがよくあります。値のバインディングやイベントリスナーの変更を手動で行うのは面倒です:

<input
  :value="text"
  @input="event => text = event.target.value">

v-model ディレクティブは、上記を単純化するのに役立ちます:

<input v-model="text">

さらに、 v-model は様々な種類の入力や <textarea> 、 <select> 要素の入力で使用することができます。使用する要素に応じて、異なる DOM プロパティとイベントのペアに自動で展開します:

  • text 型の <input> と <textarea> 要素は value プロパティと input イベントを使用します。
  • <input type="checkbox"> と <input type="radio"> は checked プロパティと change イベントを使用します。
  • <select> は value プロパティと change イベントを使用します。

Note

v-model はフォーム要素にある value 、 checked 、 selected 属性の初期値を無視します。 v-model は常に現在バインドされた JavaScript の状態を最終値のソースとして扱います。初期値の宣言は JavaScript 側で、 data オプション を使用して行ってください。

基本的な使い方

テキスト

<p>Message is: {{ message }}</p>
<input v-model="message" placeholder="edit me" />

Message is:

Try it in the Playground

Note

IME を必要とする言語 (中国語、日本語、韓国語など) では、IME による入力中に v-model が更新されないことに気づくでしょう。 もしこれらの更新にも対応したい場合は、 v-model の代わりに input イベントリスナーと value バインディングを使用してください。

複数行テキスト

<span>Multiline message is:</span>
<p style="white-space: pre-line;">{{ message }}</p>
<textarea v-model="message" placeholder="add multiple lines"></textarea>

Multiline message is:

Try it in the Playground

<textarea> 内の補間(マスタッシュが使えない)は機能しないことに注意してください。代わりに v-model を使用してください。

<!-- bad -->
<textarea>{{ text }}</textarea>

<!-- good -->
<textarea v-model="text"></textarea>

チェックボックス

単一のチェックボックス、 boolean 値:

<input type="checkbox" id="checkbox" v-model="checked" />
<label for="checkbox">{{ checked }}</label>

false

Try it in the Playground

複数のチェックボックスを同じ配列もしくは Set の値にバインドすることもできます:

export default {
  data() {
    return {
      checkedNames: []
    }
  }
}
<div>Checked names: {{ checkedNames }}</div>

<input type="checkbox" id="jack" value="Jack" v-model="checkedNames">
<label for="jack">Jack</label>

<input type="checkbox" id="john" value="John" v-model="checkedNames">
<label for="john">John</label>

<input type="checkbox" id="mike" value="Mike" v-model="checkedNames">
<label for="mike">Mike</label>

Checked names: []JackJohnMike

この場合、 checkedNames 配列には現在チェックされているボックスの値が常に格納されます。

Try it in the Playground

ラジオ

<div>Picked: {{ picked }}</div>

<input type="radio" id="one" value="One" v-model="picked" />
<label for="one">One</label>

<input type="radio" id="two" value="Two" v-model="picked" />
<label for="two">Two</label>

Picked:OneTwo

Try it in the Playground

セレクト

単一選択:

<div>Selected: {{ selected }}</div>

<select v-model="selected">
  <option disabled value="">Please select one</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Selected:Please select oneABC

Try it in the Playground

Note

もし v-model 式の初期値がどのオプションにもマッチしない場合、 <select> 要素は “unselected” 状態でレンダリングされます。 iOS では、このような場合に change イベントが発火しないため、ユーザーは最初のアイテムを選択できないことになります。したがって、上記の例のように、空の値を持つ disabled オプションを提供することが推奨されます。

複数選択(配列へのバインド):

<div>Selected: {{ selected }}</div>

<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Selected: []ABC

Try it in the Playground

セレクトオプションは v-for で動的にレンダリングすることができます:

export default {
  data() {
    return {
      selected: 'A',
      options: [
        { text: 'One', value: 'A' },
        { text: 'Two', value: 'B' },
        { text: 'Three', value: 'C' }
      ]
    }
  }
}
<select v-model="selected">
  <option v-for="option in options" :value="option.value">
    {{ option.text }}
  </option>
</select>

<div>Selected: {{ selected }}</div>

Try it in the Playground

値のバインディング

ラジオやチェックボックス、セレクトオプションにおいて、 v-model でバインディングされる値は通常は静的な文字列です (またチェックボックスでは真偽値も):

<!-- チェックされているとき `picked` は文字列 "a" -->
<input type="radio" v-model="picked" value="a" />

<!-- `toggle` は true か false のいずれか -->
<input type="checkbox" v-model="toggle" />

<!-- 最初のオプションが選択されているとき `selected` は文字列 "abc" -->
<select v-model="selected">
  <option value="abc">ABC</option>
</select>

しかし時には現在アクティブなインスタンスの動的プロパティに値をバインドしたいことがあります。それには v-bind を使用することができます。さらに、 v-bind を使用することで文字列以外の値も入力値にバインドすることができます。

チェックボックス#

<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no" />

true-value と false-value は v-model においてのみ機能する Vue 特有の属性です。ここでは toggle プロパティの値はボックスがチェックされると 'yes' がセットされ、チェックが外されると 'no' がセットされます。 v-bind を使用して動的な値にバインドすることもできます。

<input
  type="checkbox"
  v-model="toggle"
  :true-value="dynamicTrueValue"
  :false-value="dynamicFalseValue" />

Tip

ブラウザはチェックされていないボックスをフォームの送信には含めないため、 true-value と false-value 属性は入力の value 属性に影響を与えません。 2 つの値 (例、 “yes” もしくは “no” ) のうち 1 つが送信されることを保証するには、代わりにラジオを使用してください。

ラジオ

<input type="radio" v-model="pick" :value="first" />
<input type="radio" v-model="pick" :value="second" />

pick には、 1 つ目のラジオがチェックされると first の値がセットされ、 2 つ目のラジオがチェックされると second の値がセットされます。

セレクトオプション

<select v-model="selected">
  <!-- インラインのオブジェクトリテラル -->
  <option :value="{ number: 123 }">123</option>
</select>

v-model は文字列でない値のバインディングもサポートしています! 上記の例では、オプションが選択されると、 selected にはオブジェクトリテラル値である { number: 123 } がセットされます。

修飾子

.lazy

デフォルトでは、 v-model は各 input イベントの後に、入力とデータを同期します (上記 の IME による入力は例外とします)。 代わりに change イベント後に同期する lazy 修飾子を追加することができます。

<!-- "input" の代わりに "change" イベント後に同期されます -->
<input v-model.lazy="msg" />

.number

ユーザー入力を自動で数値として型変換したい場合、 v-model で管理している入力に number 修飾子を追加することができます。

<input v-model.number="age" />

もし値が parseFloat() で解析できない場合は、代わりに元の値が使用されます。

input が type="number" を持つ場合は number 修飾子が自動で適用されます。

.trim

ユーザー入力から自動で空白を取り除きたい場合、 v-model で管理している入力に trim 修飾子を追加することができます。