Vue3 — 指令(Directives)完整教學
單元:指令(Directives)
主題:v-if、v-show、v-for、v-bind、v-on
簡介
在 Vue3 中,指令是與 HTML 標籤互動的核心機制,讓開發者可以在模板(template)裡直接宣告「資料驅動的行為」。常見的五大指令 v-if、v-show、v-for、v-bind、v-on,分別負責條件渲染、顯隱切換、迭代、屬性綁定以及事件處理。掌握它們不只可以寫出簡潔的 UI 程式碼,更能提升效能、降低維護成本,是每位 Vue 開發者的必備功夫。
本篇文章以 淺顯易懂、實務導向 的方式說明這五個指令的運作原理、使用時機與常見陷阱,並提供完整的程式碼範例,適合 初學者到中級開發者 快速上手與進階應用。
核心概念
1. v-if – 條件渲染
v-if 會根據表達式的真假動態地在 DOM 中插入或移除元素。當條件為 false 時,該節點連同子樹都不會出現在實際的 DOM 裡,對瀏覽器的渲染成本最低,但每次切換都會觸發 掛載 / 銷毀 的生命週期。
<!-- 範例 1:簡單的條件渲染 -->
<div id="app">
<button @click="show = !show">
{{ show ? '隱藏' : '顯示' }} 內容
</button>
<!-- 只有 show 為 true 時才會被加入 DOM -->
<p v-if="show">這是一段只有在條件成立時才會出現的文字。</p>
</div>
// main.js
import { createApp } from 'vue'
createApp({
data() {
return { show: false }
}
}).mount('#app')
重點
v-if會在條件變化時 重新渲染 整個節點。- 適合 一次性顯示/隱藏,或是 大量 DOM 元素 只在需要時才載入的情境。
2. v-show – 顯隱切換
v-show 只會在元素上切換 CSS display: none;,不會移除或重新建立 DOM。切換成本僅是樣式的變更,適合頻繁切換的 UI(如 Tab、手風琴)。
<!-- 範例 2:切換顯示狀態 -->
<div id="app2">
<button @click="visible = !visible">
{{ visible ? '隱藏' : '顯示' }} 面板
</button>
<div v-show="visible" class="panel">
這個面板會在切換時保持在 DOM 中,只是隱藏或顯示。
</div>
</div>
// main2.js
import { createApp } from 'vue'
createApp({
data() {
return { visible: true }
}
}).mount('#app2')
重點
- 初始渲染時仍會產生完整的 DOM。
- 適合 頻繁切換、不需要掛載/銷毀生命週期 的情況。
3. v-for – 列表迭代
v-for 用於遍歷陣列或物件,產生多筆相同結構的元素。配合 :key(v-bind:key)可以讓 Vue 更精準地追蹤每筆資料的變化,避免不必要的重新渲染。
<!-- 範例 3:陣列迭代 -->
<div id="app3">
<ul>
<li v-for="(item, index) in fruits" :key="item.id">
#{{ index + 1 }} {{ item.name }} — 價格:{{ item.price }} 元
</li>
</ul>
</div>
// main3.js
import { createApp } from 'vue'
createApp({
data() {
return {
fruits: [
{ id: 1, name: '蘋果', price: 30 },
{ id: 2, name: '香蕉', price: 20 },
{ id: 3, name: '芒果', price: 45 }
]
}
}
}).mount('#app3')
進階寫法:同時遍歷 物件 時可以使用 (value, key, index) in object。
<div id="app4">
<table>
<tr v-for="(val, key, i) in userInfo" :key="key">
<td>{{ i + 1 }}</td>
<td>{{ key }}</td>
<td>{{ val }}</td>
</tr>
</table>
</div>
createApp({
data() {
return {
userInfo: {
姓名: '王小明',
年齡: 28,
城市: '台北'
}
}
}
}).mount('#app4')
重點
- 必須提供 唯一的
key,否則會產生渲染警告或效能下降。 v-for內部不建議使用v-if,因為每次迭代都會重新計算條件,建議改用 計算屬性 先過濾資料。
4. v-bind – 動態屬性綁定
v-bind(簡寫 :)可以把 JavaScript 表達式 的值綁定到 HTML 屬性、class、style 等。它讓模板與資料保持同步,避免手動拼接字串。
<!-- 範例 4:屬性與 class 動態綁定 -->
<div id="app5">
<img :src="imgUrl" :alt="imgAlt" />
<button :class="{ active: isActive }" @click="toggle">
{{ isActive ? '已啟用' : '已停用' }}
</button>
</div>
createApp({
data() {
return {
imgUrl: 'https://picsum.photos/200',
imgAlt: '隨機圖片',
isActive: false
}
},
methods: {
toggle() {
this.isActive = !this.isActive
}
}
}).mount('#app5')
技巧
- 綁定多個 class:
:class="[classA, classB]"或:class="{classA:true, classB:false}" - 綁定 style:
:style="{ color: textColor, fontSize: fontSize + 'px' }"
5. v-on – 事件監聽
v-on(簡寫 @)用於 監聽 DOM 事件,並在事件觸發時呼叫 Vue 方法或執行內聯表達式。支援修飾符(.stop、.prevent、.once、.capture 等)來調整事件行為。
<!-- 範例 5:表單提交與鍵盤事件 -->
<div id="app6">
<form @submit.prevent="handleSubmit">
<input v-model="name" @keyup.enter="handleEnter" placeholder="輸入姓名" />
<button type="submit">送出</button>
</form>
<p>你輸入的名字是:{{ name }}</p>
</div>
createApp({
data() {
return { name: '' }
},
methods: {
handleSubmit() {
alert(`送出資料:${this.name}`)
},
handleEnter() {
console.log('Enter 鍵被按下,當前輸入值:', this.name)
}
}
}).mount('#app6')
常用修飾符
| 修飾符 | 功能 |
|---|---|
.stop |
停止事件冒泡 (event.stopPropagation()) |
.prevent |
防止預設行為 (event.preventDefault()) |
.once |
只觸發一次 |
.capture |
以捕獲階段監聽 |
.passive |
告訴瀏覽器事件不會呼叫 preventDefault(),提升滾動效能 |
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
v-if 與 v-for 同時使用 |
每次迭代都會重新評估條件,導致效能下降。 | 先在 computed 中過濾資料,再只使用 v-for。 |
忘記加 :key |
Vue 會使用索引作為 key,導致列表重排時狀態錯亂(例如表單輸入被清空)。 | 為每筆資料提供唯一且穩定的 id 作為 key。 |
v-show 仍渲染大量 DOM |
隱藏的元素仍佔用記憶體與渲染成本。 | 若元素本身非常龐大且不常顯示,改用 v-if。 |
過度使用 v-bind 產生大量 inline style |
會讓瀏覽器無法有效利用 CSS 快取。 | 將樣式抽離為 class,僅在必要時才使用 style 綁定。 |
| 事件冒泡未處理 | 例如在父層有 @click,子層的 @click 也會觸發。 |
使用 .stop 或在子層方法內 event.stopPropagation()。 |
最佳實踐
- 選擇正確的指令:
v-if用於「是否需要渲染」的情況,v-show用於「頻繁切換顯隱」的情況。 - 保持資料單向流:指令只負責「呈現」或「事件觸發」,資料變更仍應透過
data、computed、store(Pinia/Vuex)來管理。 - 使用
:key防止重渲染:尤其在表單、動畫、或含有內部狀態的子元件時。 - 避免在模板裡寫過於複雜的表達式:保持模板簡潔,將邏輯搬到
computed或methods中。 - 善用修飾符:減少在方法裡手動
event.preventDefault(),提升可讀性。
實際應用場景
| 場景 | 建議指令組合 | 為什麼 |
|---|---|---|
| 使用者登入後才顯示個人資訊 | v-if(判斷 isLoggedIn)+ v-bind(綁定資料) |
登入狀態改變時才需要掛載個人資訊元件,減少不必要的渲染。 |
| 手機版的手風琴選單 | v-show(切換展開/收合)+ v-on:click.stop |
切換頻繁且需要保持已渲染的子項目狀態。 |
| 商品列表與過濾功能 | v-for + computed(過濾結果)+ :key |
只渲染符合條件的商品,避免在 v-for 裡直接使用 v-if。 |
| 動態圖片切換 | v-bind:src + @click(切換圖片) |
讓圖片來源直接對應資料屬性,保持 UI 與狀態同步。 |
| 表單驗證與即時回饋 | v-model + @input(即時檢查)+ v-show(錯誤訊息) |
錯誤訊息只需要隱藏/顯示,避免每次驗證時重新掛載錯誤元件。 |
總結
Vue3 的五大指令 v-if、v-show、v-for、v-bind、v-on,分別負責 條件渲染、顯隱切換、列表迭代、屬性綁定與事件監聽。熟練掌握它們的運作機制與使用時機,能讓開發者寫出 高效、可維護且易於擴充 的介面。
- 選擇適當指令:根據「是否需要掛載」或「是否頻繁切換」做判斷。
- 永遠提供唯一
key:避免列表渲染的狀態錯亂。 - 保持模板簡潔:將複雜邏輯搬到
computed/methods中。 - 善用修飾符:減少手動
event處理,提升可讀性。
透過本文提供的 實務範例、陷阱辨識 與 最佳實踐,你可以在日常開發中快速套用這些指令,從簡單的條件顯示到複雜的動態列表,都能游刃有餘。祝你在 Vue3 的世界裡寫出更乾淨、更強大的程式碼! 🚀