在 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