本文 AI 產出,尚未審核

Vue3 — 指令(Directives)完整教學

單元:指令(Directives)
主題v-ifv-showv-forv-bindv-on


簡介

在 Vue3 中,指令是與 HTML 標籤互動的核心機制,讓開發者可以在模板(template)裡直接宣告「資料驅動的行為」。常見的五大指令 v-ifv-showv-forv-bindv-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 用於遍歷陣列或物件,產生多筆相同結構的元素。配合 :keyv-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-ifv-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()

最佳實踐

  1. 選擇正確的指令v-if 用於「是否需要渲染」的情況,v-show 用於「頻繁切換顯隱」的情況。
  2. 保持資料單向流:指令只負責「呈現」或「事件觸發」,資料變更仍應透過 datacomputedstore(Pinia/Vuex)來管理。
  3. 使用 :key 防止重渲染:尤其在表單、動畫、或含有內部狀態的子元件時。
  4. 避免在模板裡寫過於複雜的表達式:保持模板簡潔,將邏輯搬到 computedmethods 中。
  5. 善用修飾符:減少在方法裡手動 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-ifv-showv-forv-bindv-on,分別負責 條件渲染、顯隱切換、列表迭代、屬性綁定與事件監聽。熟練掌握它們的運作機制使用時機,能讓開發者寫出 高效、可維護且易於擴充 的介面。

  • 選擇適當指令:根據「是否需要掛載」或「是否頻繁切換」做判斷。
  • 永遠提供唯一 key:避免列表渲染的狀態錯亂。
  • 保持模板簡潔:將複雜邏輯搬到 computed / methods 中。
  • 善用修飾符:減少手動 event 處理,提升可讀性。

透過本文提供的 實務範例陷阱辨識最佳實踐,你可以在日常開發中快速套用這些指令,從簡單的條件顯示到複雜的動態列表,都能游刃有餘。祝你在 Vue3 的世界裡寫出更乾淨、更強大的程式碼! 🚀