在 Vue 的宇宙裡,表單輸入綁定不再是令人頭痛的問題!有了 v-model,你只需要一句簡單的指令,就可以讓使用者的輸入與你的應用程式完美同步。無論是輸入框、複選框、還是下拉選單,v-model 都幫你搞定!今天就讓我們來看看這個神奇的綁定指令如何讓一切變得超級簡單吧!😎
前言沒有梗,就還是請語言模型寫。

但但但但但是!為什麼需要它呢?
cumbersome,翻譯:笨重的;累贅的;低效的。
當前端處理表單時,若要獲取表單上使用者輸入的值,進而同步到介面或某些邏輯,可能需要手動的賦值、綁定。
這是一個手動處理 將 input 輸入值同步到介面上 的簡單例子:
<script setup>
import { ref } from "vue";
const text = ref("");
</script>
<template>
  <div>
    <input
      :value="text"
      @input="(event) => (text = event.target.value)"
      placeholder="請輸入一些內容..."
    />
    <p>當前輸入的內容是:{{ text }}</p>
  </div>
</template>
text 為響應式內容 "",將其綁定到模板上 {{ text }}。@input 為 input 的監聽事件,若使用者輸入文字,將會觸發 (event) => (text = event.target.value),是一個內聯事件處理器,event 為事件物件,而箭頭函式將會把當下的 event.target.value 「賦值」給 text,達到更新資料的行為。<input :value="text" />::value 會將 text 綁定到 input 的 value 值上,因此輸入框的資料會和模板上文本插值內容同步。會藉由以上幾個步驟,達成資料、介面同步的「雙向綁定」效果。
官方提到:手動連接值綁定和更改事件監聽器可能會很麻煩
所以!Vue 傳喚了小幫手 v-model 幫助我們解決這些問題。
用於實現:表單元素與響應式數據之間的雙向綁定。
讓使用者輸入的內容自動反映到資料中,若有資料的變更也會即時更新到使用者的輸入欄位。
<要綁定的元素 v-model="要與元素綁定的數據">
例如:在 input 上定義了 value 屬性、並且綁定了 v-model:
<script setup>
import { ref } from "vue";
const text = ref("");
</script>
<template>
  <input v-model="text" value="會忽略我"> 
  <p>目前輸入的內容是:{{ text }}</p>
</template>
Vue 會自動忽略綁定的 value 屬性,而永遠指向 v-model 綁定的響應式狀態。
| 所綁定的元素 | 對應屬性 | 監聽事件 | 
|---|---|---|
| input text | value | input | 
| textarea | value | input | 
| checkbox | checked | change | 
| radio | checked | change | 
| select | value | change | 
當綁定了元素,v-model 會自動設置元素要對應到的「屬性、監聽事件」。
例如:綁定了 textarea,v-model 就知道要幫我們綁上 value 屬性,並監聽 input 事件。
接下來讓我們看看這些表單輸入綁定的範例吧!
v-model 將 text 綁定到輸入框,監聽 input 事件。text 的初始值,設為響應式狀態的空字串。input 事件觸發,input 的 value 被傳到 text 中。text 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const text = ref("");
</script>
<template>
  <h3>input text</h3>
  <input v-model="text" />
  <p>你輸入的內容是:{{ text }}</p>
</template>

v-model 將 textarea 綁定到輸入框,監聽 input 事件。textarea 的初始值,設為響應式狀態的空字串。input 事件觸發,input 的 value 被傳到 textarea 中。textarea 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const textarea = ref("");
</script>
<template>
  <h3>textarea</h3>
  <textarea v-model="textarea" placeholder="請輸入一些內容..." />
  <p>你輸入的內容是:{{ textarea }}</p>
</template>

注意以下語法是無效的喔。
<textarea>{{ someText }}</textarea> <!-- 無效 -->
v-model 將 isCheckedSingle 綁定到輸入框,監聽 change 事件。isCheckedSingle 的初始值,設為響應式狀態的 false。change 事件觸發,input 的 value 被傳到 isCheckedSingle 中。isCheckedSingle 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const isCheckedSingle = ref(false);
</script>
<template>
  <div>
    <h3>單選 checkbox</h3>
    <input type="checkbox" id="checkbox" v-model="isCheckedSingle" />
    <label for="checkbox">點選選項</label>
    <p>是否選取? {{ isCheckedSingle }}</p>
  </div>
</template>

v-model 將 isCheckedMultiple 綁定到輸入框,監聽 change 事件。isCheckedMultiple 的初始值,設為響應式狀態的「空陣列」。change 事件觸發,input 的 value 被傳到 isCheckedMultiple 中。isCheckedMultiple 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const isCheckedMultiple = ref([]);
</script>
<template>
  <div>
    <h3>多選 checkbox</h3>
    <input type="checkbox" id="Jami" value="Jami" v-model="isCheckedMultiple" />
    <label for="Jami">Jami</label>
    <input
      type="checkbox"
      id="Irene"
      value="Irene"
      v-model="isCheckedMultiple"
    />
    <label for="Irene">Irene</label>
    <input
      type="checkbox"
      id="Jenny"
      value="Jenny"
      v-model="isCheckedMultiple"
    />
    <label for="Jenny">Jenny</label>
    <p>你選擇的選項是:{{ isCheckedMultiple.join() }}</p>
  </div>
</template>

v-model 將 selectedOption 綁定到輸入框,監聽 change 事件。selectedOption 的初始值,設為響應式狀態的「空字串」。change 事件觸發,input 的 value 被傳到 selectedOption 中。selectedOption 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const selectedOption = ref("");
</script>
<template>
  <div>
    <label>
      <input type="radio" value="選項一" v-model="selectedOption" />
      選項一
    </label>
    <label>
      <input type="radio" value="選項二" v-model="selectedOption" />
      選項二
    </label>
    <p>你選擇的選項是:{{ selectedOption }}</p>
  </div>
</template>

v-model 將 isSelected 綁定到輸入框,監聽 change 事件。isSelected 的初始值,設為響應式狀態的「空字串」。change 事件觸發,input 的 value 被傳到 isSelected 中。isSelected 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const isSelected = ref("");
</script>
<template>
  <div>
    <h3>select</h3>
    <select v-model="isSelected">
      <option value="" disabled>請選擇</option>
      <option value="選項一">選項一</option>
      <option value="選項二">選項二</option>
      <option value="選項三">選項三</option>
    </select>
    <p>Select 當前狀態:{{ isSelected }}</p>
  </div>
</template>
注意:預設選項的如果都不是任何其他選項,為了確保用戶體驗,官方建議設置一個預設的選項,並設置 value="" 和 disabled 屬性。
這樣可以避免用戶在選擇時出現問題,確保能夠正確觸發 change 事件。

v-model 將 isSelectedMultiple 綁定到輸入框,監聽 change 事件。isSelectedMultiple 的初始值,設為響應式狀態的空字串。change 事件觸發,input 的 value 被傳到 isSelectedMultiple 中。isSelectedMultiple 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const isSelectedMultiple = ref([]);
</script>
<template>
  <div>
    <h3>select multiple</h3>
    <select v-model="isSelectedMultiple" multiple>
      <option value="選項一">選項一</option>
      <option value="選項二">選項二</option>
      <option value="選項三">選項三</option>
    </select>
    <p>Select 當前狀態:{{ isSelectedMultiple }}</p>
  </div>
</template>

v-for 渲染v-model 將 isSelectedVFor 綁定到輸入框,監聽 change 事件。isSelectedVFor 的初始值,設為響應式狀態的「ㄧ」文字。change 事件觸發,input 的 value 被傳到 isSelectedVFor 中。isSelectedVFor 的內容即時渲染到模板上。<script setup>
import { ref } from "vue";
const isSelectedVFor = ref(`ㄧ`);
const options = [
  { title: `選項一`, value: `一` },
  { title: `選項二`, value: `二` },
  { title: `選項三`, value: `三` },
];
</script>
<template>
  <div>
    <h3>select v-for</h3>
    <select v-model="isSelectedVFor">
      <option value="" disabled>請選擇</option>
      <option v-for="option in options" :value="option.value">
        {{ option.title }}
      </option>
    </select>
    <p>選項{{ isSelectedVFor }}</p>
  </div>
</template>
通常 checkbox、radio、select 在 v-model 上綁定的值都是單一靜態字串(單選 select 綁 boolean 值),但若我們想要讓其綁定動態數據,可以用 v-bind 綁定表達式,讓屬性綁定為自定義的動態值。
官方文件:但有時我們可能希望將該值綁定到當前組件實例上的動態數據。這可以通過使用 v-bind 來實現。此外,使用 v-bind 還使我們可以將選項值綁定為非字符串的數據類型。
直接來看看在使用上的範例吧~
<input
  type="checkbox"
  v-model="綁定的數據"
  true-value="yes"
  false-value="no" />
true-value 和 false-value 是 Vue 在 v-model 中的特殊屬性,用來定義 checkbox 勾選/未勾選時的 value,在這,綁定的數據會在:
yes。no。這兩個值可以確保:無論使用者的選擇是什麼,都有值可以提交,因為使用者的選擇,對於表單提交功能來說是很重要的!
但官方文件提到:如果不想設置這兩個屬性的話,建議使用 radio,radio 是單選,確保了每個選項都會寫入值。
<input
  type="checkbox"
  v-model="綁定的數據"
  :true-value="自定義的true動態值的表達式"
  :false-value="自定義的false動態值的表達式" />
我們以一個範例來看預設值/自定義值的差別~
<script setup>
import { ref } from "vue";
const isChecked = ref("");
const isCheckedCustom = ref("");
const customTrueValue = ref("自定義的true動態值");
const customFalseValue = ref("自定義的false動態值");
</script>
<template>
  <div>
    <h3>單選 checkbox toggle yes/no</h3>
    <input
      type="checkbox"
      id="checkbox"
      v-model="isChecked"
      true-value="yes"
      false-value="no"
    />
    <label for="checkbox">點選選項</label>
    <p>是否選取? {{ isChecked }}</p>
  </div>
  <div>
    <h3>單選 checkbox toggle 自定義的動態值</h3>
    <input
      type="checkbox"
      id="isCheckedCustom"
      v-model="isCheckedCustom"
      :true-value="customTrueValue"
      :false-value="customFalseValue"
    />
    <label for="isCheckedCustom">點選選項</label>
    <p>是否選取? {{ isCheckedCustom }}</p>
  </div>
</template>

<input type="radio" v-model="綁定的數據" :value="自定義的表達式" />你的第一個選項
<input type="radio" v-model="綁定的數據" :value="自定義的表達式" />你的第二個選項
我們可以這樣設定:
<script setup>
import { ref } from "vue";
const selectedOption = ref("");
const selectedFirstValue = ref("自定義的選項一的值");
const selectedSecondValue = ref("自定義的選項二的值");
</script>
<template>
  <div>
    <h3>radio</h3>
    <label>
      <input
        type="radio"
        v-model="selectedOption"
        :value="selectedFirstValue"
      />
      選項一
    </label>
    <label>
      <input
        type="radio"
        v-model="selectedOption"
        :value="selectedSecondValue"
      />
      選項二
    </label>
    <p>你選擇的選項是:{{ selectedOption }}</p>
  </div>
</template>

也可以綁定非字串的值。
這邊以 {} 作為範例。
<select v-model="綁定的數據">
  <option :value="{ 物件屬性: 物件 value }"></option>
</select>
上範例:
<script setup>
import { ref } from "vue";
const isSelected = ref("");
</script>
<template>
  <div>
    <h3>select</h3>
    <select v-model="isSelected">
      <option :value="" disabled>請選擇</option>
      <option :value="{ option: 1 }">選項一</option>
      <option :value="{ option: 2 }">選項二</option>
      <option :value="{ option: 3 }">選項三</option>
    </select>
    <p>Select 當前狀態:{{ isSelected }}</p>
  </div>
</template>

v-model 的預設行為會是 input 事件後更新數據,lazy 可使它更改為在 change 事件後更新數據。
<input v-model.lazy="綁定的數據" />
預設將使用者輸入框內容轉為數字,如果該值無法被 parseFloat() 處理,會 return 原始的值。
<input v-model.number="綁定的數據" />

預設自動去除使用者輸入框內容兩端的空格。
<input v-model.trim="綁定的數據" />

這種操作方式真的直觀多了,超讚的 QQ
跟著官網的列表順序看文件,list 不知不覺往下往下再往下,本菜感覺 Vue 已經準備要帶我進入到另一個的異世界去了,但如 Day1 說的!!!士氣必須得繼續の高昂下去,誰怕誰的樣子要先裝出來。
OK 明天準備撞進「生命週期」(對沒有錯就是那張圖)

https://github.com/Jamixcs/2024iThome-jamixcs/tree/main/src/components/day23