Vue.js (5) - 表單資料雙向綁定指令

Vue.js

對於表單元素,Vue.js 提供一個專用的指令,可以讓你將 View 及資料建立雙向綁定。當雙向資料綁定建立之後,使用者輸入的內容會自動儲存到一個變數中,同時,這個變數的資料會被更新到所有和它綁定的 View 中,看起來就像是立即的資料同步。

關於雙向綁定

在表單元素中,我們要偵聽使用者的輸入,同時做出必要的資料更新,也就是同時做兩件事,雖然這麼做很容易,例如以下範例:
HTML<div id="vm">
  <input @keyup="onInput" :value="txt">
  {{ txt }}
</div>

<script>
new Vue({
  el: '#vm',
  data: {
    txt: ''
  },
  methods: {
    onInput: function (event) {
      this.txt = event.target.value
    }
  }
})
</script>
當你在輸入框中輸入任何內容,都會在放開按鍵時觸發事件,於是修改的資料 txt 會立即反應在 {{ txt }} 區塊中。當你手動修改 txt 的值,它的更動也會立即呈現在 <input>{{ txt }} 中。

也就是說,View (這裡的 <input>{{ txt }}) 和資料 (這裡的 txt) 做了綁定,於是資料改變,View 跟著變;同時,資料 (這裡的 txt) 也和 View (這裡的 <input> ) 做了綁定(這裡透過事件的觸發),於是 View (這裡的 <input> ) 的內容改變,資料也就跟著變。

這麼做其實太複雜了,你可以想像當網站功能變多時會是什麼情況。Vue.js 提供了一個更容易使用的指令 v-model 來做這件事,使用它,你就不用寫得像前面的範例一樣複雜,當網站的功能變多時,你的程式碼仍可以保持精簡,程式碼越少,就越不容易犯錯。看看用 v-model 的範例:
HTML<div id="vm">
  <input v-model="txt">
  {{ txt }}
</div>

<script>
new Vue({
  el: '#vm',
  data: {
    txt: ''
  }
})
</script>
v-model 實際上就是在做前一個範例中所做的事,當你瞭解它在做什麼,看起來就不會覺得太神奇了。

v-model

雙向資料綁定的指令有些限制,只能在表單元素或 Vue 元件上使用:
  • <input>
  • <select>
  • <textarea>
  • Vue Components
另外有提供 3 個修飾符號:
  • .lazy:取代 oninput 改為偵聽 onchange 事件
  • .number:字串轉為數字
  • .trim:去除首尾空格

單行輸入框 (input)

在前面的範例中就已經說明如何使用,這裡就不重覆。

多行輸入框 (textarea)

使用範例:
HTML<div id="vm">
  Content:
  <pre>{{ content }}</pre>
  <br>
  <textarea v-model="content"></textarea>
</div>

<script>
var vm = new Vue({
  el: '#vm',
  data: {
    content: ''
  }
})
</script>
其實和 <input> 是一樣的。這裡要注意,在 <textarea>{{ content }}</textarea> 中使用雙括號 {{ }} 插入資料的方式是無效的,只能用 v-model

複選按鈕 (checkbox)

使用範例:
HTML<div id="vm">
  <label>
    <input type="checkbox" v-model="chkAnswer">{{ chkAnswer }}
  </label>
</div>

<script>
var vm = new Vue({
  el: '#vm',
  data: {
    chkAnswer: false
  }
})
</script>
當你按一下複選按鈕,如果勾選的話,chkAnswer 就會變成 true ;反之則是 false。

要在多個項目中複選,只要將 v-model 指定同一個名稱即可,這些按鈕就會視為同一群組:
HTML<div id="vm">
  <label>
    <input type="checkbox" 
           value="Miss Fortune" 
           v-model="chkCharacters">Miss Fortune
  </label>
  <br>
  <label>
    <input type="checkbox" 
           value="Akali" 
           v-model="chkCharacters">Akali
  </label>
  <br>
  <label>
    <input type="checkbox" 
           value="Caitlyn" 
           v-model="chkCharacters">Caitlyn
  </label>
  <hr>
  選擇的角色:
  <ul>
    <li v-for="character in chkCharacters">{{ character }}</li>
  </ul>
</div>

<script>
var vm = new Vue({
  el: '#vm',
  data: {
   chkCharacters: []
  }
})
</script>
輸出結果:

單選按鈕 (Radio)

Checkbox 是用來複選的;Radio 則是用來單選的。
你可以將前面的複選範例中的 type="checkbox" 換成 type="radio" 就變成單選了,例如:
HTML<div id="vm">
  <label>
    <input type="radio" 
           value="Miss Fortune" 
           v-model="character">Miss Fortune
  </label>
  <br>
  <label>
    <input type="radio" 
           value="Akali" 
           v-model="character">Akali
  </label>
  <br>
  <label>
    <input type="radio" 
           value="Caitlyn" 
           v-model="character">Caitlyn
  </label>
  <hr>
  選擇的角色:{{ character }}
</div>

<script>
var vm = new Vue({
  el: '#vm',
  data: {
    character: ''
  }
})
</script>
因為是單選,所以資料值就只是字串,而不是陣列。
輸出結果:

下拉式選單 (select)

使用範例:
HTML<div id="vm">
  <select v-model="character">
    <option>Miss Fortune</option>
    <option>Akali</option>
    <option value="Cait.">Caitlyn</option>
  </select>
  <br>
  選擇的角色:{{ character }}
</div>

<script>
new Vue({
  el: '#vm',
  data: {
    character: ''
  }
})
</script>
<select> 元素上透過 v-model 雙向綁定 character 這個資料屬性,當其中一個 <option> 被選中時,它的內容或值 (value) 就會存入 character 資料屬性中。<option> 如果沒有指定 value 屬性,它包含的內容會被當成值。
輸出結果:
如果要複選的話,要在 <select> 元素加上 multiple 屬性。同時,你的資料屬性現在是陣列了,而不是字串,所以我們修改它的名稱後面加上 s 來明確它的內容:
HTML<div id="vm">
  <select v-model="characters" multiple>
    <option>Miss Fortune</option>
    <option>Akali</option>
    <option>Caitlyn</option>
  </select>
  <br>
  選擇的角色:
  <ul>
    <li v-for="c in characters">{{ c }}</li>
  </ul>
</div>

<script>
new Vue({
  el: '#vm',
  data: {
    characters: []
  }
})
</script>
輸出結果:
很多時候,你的 <option> 是由資料動態建立的,這時候就要把之前學到的東西拿來用用看了。

<select> 上用 v-model 綁定的資料是被選中的項目;透過 v-for 重覆執行要建立的 <option>,同是用 v-bind:value (簡寫 :value) 來綁定 value 屬性,最後用雙括號 {{ }} 插入文字內容:
HTML<div id="vm">
  <select v-model="character">
    <option v-for="c in characters" :value="c.value">
      {{ c.text }}
    </option>
  </select>
  <br>
  選擇的角色:{{ character }}
</div>

<script>
new Vue({
  el: '#vm',
  data: {
    character: '',
    characters: [
      {text: 'Miss Fortune', value: 'MF'},
      {text: 'Akali', value: 'Ak'},
      {text: 'Caitlyn', value: 'CA'}
    ]
  }
})
</script>
這裡的 characters 給選單用的資料是個陣列,每一個項目都是一個值物件,其中有兩個自定的屬性 textvalue。在實際應用上,這裡的資料通常會是從伺服器上下載下來後指定的。 假如你在瀏覽器(這裡用 Firefox)的主控台,輸入
vm.__vue__.characters.push({text:'Irelia', value:'IR'})
註:在 JSFiddle 中必須切換目標文件為 https://fiddle.jshell.net/_display/ 才能執行。

這是模擬非同步的行為,當資料從伺服器下載完成,直接改變資料,頁面上的 <option> 項目就會立即改變,不需要重新整理頁面。

修飾符號

.lazy
v-modelinput 事件中,預設會同步輸入框的資料,也就是你輸入什麼字就立即反應。如果你加上 .lazy ,就會改成在 onchange 事件觸發時才同步,也就是輸入框失去焦點時:
HTML<input v-model.lazy="text">
直接在 v-model 後面接上 .lazy 就可以了。
.number
如果你要將使用者的輸入轉為 Number 型態,可以加上 .number ,如果輸入值可以轉成 Number 就將它轉換:
HTML<input v-model.number="age" type="number">
會有這個修飾符號的原因是,即使輸入框被註明為 type="number",它的回傳值依然是字串。
.trim
很多時候你會用 Javascript 的 trim() 函式將字串值的前後空格去除,.trim 可以直接幫你做到:
HTML<input v-model.trim="text">
它不是即時同步,而是在 onchange 時才執行。
本文網址:http://blog.tonycube.com/2017/04/vuejs-5-form.html
Tony Blog 撰寫,請勿全文複製,轉載時請註明出處及連結,謝謝 😀

我要留言

留言小提醒:
1.回覆時間通常在晚上,如果太忙可能要等幾天。
2.請先瀏覽一下其他人的留言,也許有人問過同樣的問題。
3.程式碼請先將它編碼後再貼上。(線上編碼:http://bit.ly/1DL6yog)
4.文字請加上標點符號及斷行,難以閱讀者恕難回覆。
5.感謝您的留言,您的問題也可能幫助到其他有相同問題的人。