---
# System prepended metadata

title: Vue.js 學習旅程Mile 14 – Form Input Bindings 表單綁定篇：v-model
tags: [w3HexSchool, Javascript, Vue]

---

# Vue.js 學習旅程Mile 14 – Form Input Bindings 表單綁定篇：v-model
###### tags: `w3HexSchool` `Vue` `Javascript`

## 基本用法
使用 `v-model` 可以對表單元素 `<input>`、`<textarea>` 及 `<select>` 進行資料的雙向綁定。
雙向綁定的意思是，`data` 驅動 `view`，也能從 `view` 改變 `data`。
`v-model` 其實是一種語法糖 (syntax sugar)，結合 `v-bind` (data binding) 與 `v-on` (event handling)。

`v-model` 針對不同的表單元素使用不同的屬性 property 與事件：

* `text` 和 `textarea` 元素使用 `value` property 和 `input` 事件
* `checkbox` 和 `radio` 使用 `checked` property 和 `change` 事件
* `select` 元素將 value 作為 `prop` 並將 `change` 作為事件

#### 注意
* `v-model` 會忽略所有表單元素的 `value`、`checked`、`selected` 這些屬性 attribute 的初始值。因此必須在一開始建立 Vue 實體時的 `data` 內宣告，才能達到響應式互動。

* 中文、日文或是韓文的輸入法會需要將多個字組合後才會變為一個完整的字，例如中文的嗨就需要鍵入ㄏㄞˋ後按下 Enter 鍵才會輸入， `v-model` 並不會在拼音時就更新資料，而是會在按下 Enter 後才更新，因此如果想要讓資料在拼音時即時響應，可以直接使用 `input` 事件實作。
  * 補充：IME，input method editor 輸入法編輯器。可將輸入的按鍵轉換成其他語言的字元。例如常見的：注音輸入法編輯器、倉頡輸入法編輯器等。

```htmlmixed=
<div>
  <button @click="msg=''">Clear</button>
  <input placeholder="Use IME" :value="msg" @input="msg=$event.target.value">
  {{msg}}
</div>
```


### 單行文字 `<input type="text">`
`text` 綁定的是字串

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

### 多行文字 `<textarea>`
`textarea` 綁定的是字串

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


### 複選框 `<input type="checkbox">`

#### 單一複選框

單一 `checkbox` 綁定的是布林值，判斷這個選項是否有勾選

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

#### 多個複選框

多個 `checkbox` 綁定的是陣列，當有勾選時，綁定的資料陣列會加上這個 `input` 標籤的 `value` 屬性值

```htmlmixed=
<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>
<br>
<span>Checked names: {{ checkedNames }}</span>
```
```javascript=
new Vue({
  el: '...',
  data: {
    checkedNames: []
  }
})
```

### 單選按鈕 `<input type="radio">`

`radio` 綁定的是字串

```htmlmixed=
<input type="radio" id="one" value="One" v-model="picked">
<label for="one">One</label>
<br>
<input type="radio" id="two" value="Two" v-model="picked">
<label for="two">Two</label>
<br>
<span>Picked: {{ picked }}</span>
```

### 選擇框 `<select>`

#### 單選選擇框 

單選 `select` 綁定的是字串

```htmlmixed=
<div id="example-5">
  <select v-model="selected">
    <option disabled value="">請選擇</option>
    <option>A</option>
    <option>B</option>
    <option>C</option>
  </select>
  <span>Selected: {{ selected }}</span>
</div>
```
```javascript=
new Vue({
  el: '...',
  data: {
    selected: ''
  }
})
```

#### 注意事項

如果初始值沒有符合任何的選項時， `select` 標籤會處於未選擇的狀態，也就是選項框中沒有任何值，在 IOS 下會有問題，因此最好的方法就是增加一個初始的選項，像是 `<option disabled value="">Please select one</option>` 來解決此問題。

#### 複選選擇框

複選 `select` (加上 `multiple` 屬性) 綁定的是陣列

```htmlmixed=
<select v-model="selected" multiple>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>
<br>
<span>Selected: {{ selected }}</span>
```

##### 用 `v-for` 渲染動態選項

```htmlmixed=
<select v-model="selected">
  <option v-for="option in options" v-bind:value="option.value">
    {{ option.text }}
  </option>
</select>
<span>Selected: {{ selected }}</span>
```
```javascript=
new Vue({
  el: '...',
  data: {
    selected: 'A',
    options: [
      { text: 'One', value: 'A' },
      { text: 'Two', value: 'B' },
      { text: 'Three', value: 'C' }
    ]
  }
})
```

## 動態值綁定
把 `value` 動態綁定在 Vue 實體中的資料屬性上

### 複選框 `<input type="checkbox">`
`checkbox` 使用 `true-value` 及 `false-value` 分別綁定勾選及未勾選時的資料


```htmlmixed=
<input
  type="checkbox"
  v-model="toggle"
  true-value="yes"
  false-value="no"
>
```
```javascript=
// when checked:
vm.toggle === 'yes'
// when unchecked:
vm.toggle === 'no'
```

#### 注意

這裡的 `true-value` 和 `false-value` attribute 並不會影響輸入控件的 `value` attribute，因為瀏覽器在提交表單時不會包含未被選中的複選框。如果要確保表單中這兩個值中的一個能夠被提交，(即“yes”或“no”)，請改用單選按鈕 `radio`。

### 單選按鈕 `<input type="radio">`

```htmlmixed=
<input type="radio" v-model="pick" v-bind:value="a">
```
```javascript=
// when checked:
vm.pick === vm.a
```

### 選擇框的選項 `<select>`
```htmlmixed=
<select v-model="selected">
  <!-- inline object literal -->
  <option v-bind:value="{ number: 123 }">123</option>
</select>
```
```javascript=
// when selected:
typeof vm.selected // => 'object'
vm.selected.number // => 123
```

## 修飾符 

### `.lazy`
原本的 `v-model` 會在 `input` 事件觸發時更新資料，加上 `.lazy` 修飾符後，更新的時間點會被延到 `change` 事件時。因此如果加上 `.lazy` ，要在離開輸入框時才會更新資料

```htmlmixed=
<!-- synced after "change" instead of "input" -->
<input v-model.lazy="msg">
```

### `.number`

如果想讓輸入框的值其型別為數字，必須要使用 `.number` 修飾符

> 因為 HTML 的輸入框就算是 `type="number"` ，輸入值的型別也還是字串

```htmlmixed=
<input v-model.number="age" type="number">
```

### `.trim`

去除首尾空白

```htmlmixed=
<input v-model.trim="msg">
```

## 參考資料
* [Vue.js - Form Input Bindings](https://vuejs.org/v2/guide/forms.html)
* [Vue.js: data、v-model 與雙向綁定](https://cythilya.github.io/2017/04/14/vue-data-v-model/)
* [Vue.js Core 30天屠龍記(第19天): 表單綁定](https://ithelp.ithome.com.tw/articles/10207739)
* [輸入法 (IME)](https://www.google.com/intl/zh-TW/inputtools/services/features/input-method.html#tab=cangjie)
