Vue 3 基礎概念 — 模板語法(Template Syntax)
簡介
在 Vue 3 中,模板語法是連結 UI 與資料的橋樑。開發者只需要在 .vue 檔的 <template> 區塊寫類似 HTML 的標記,即可讓畫面自動根據資料變化而更新。掌握模板語法不僅能快速構建介面,還能避免大量的 DOM 操作,讓程式碼更具可讀性與可維護性。
本篇文章以 Vue 3 為前提,說明最常用的模板指令、插值、條件與迴圈渲染等核心概念,並提供實作範例與最佳實踐,幫助你在實務專案中快速上手、減少錯誤。
核心概念
1. 資料插值(Interpolation)
最基本的模板語法是 雙大括號 {{ }},用來把 JavaScript 表達式的結果渲染到 HTML 中。
<template>
<h1>歡迎,{{ user.name }}!</h1>
<p>今天是 {{ new Date().toLocaleDateString() }}。</p>
</template>
<script setup>
import { ref } from 'vue'
const user = ref({ name: '小明' })
</script>
{{ }}內只能放單行表達式,不允許使用語句(如if、for)。- 只要
user.name的值變動,對應的文字會即時更新。
2. 指令(Directives)
指令是以 v- 開頭的特殊屬性,提供 條件渲染、迴圈、事件綁定 等功能。最常見的有:
| 指令 | 功能說明 | 範例 |
|---|---|---|
v-bind / : |
動態綁定 HTML 屬性 | <img :src="imgUrl" alt="圖片"> |
v-on / @ |
綁定事件監聽器 | <button @click="increment">+</button> |
v-if / v-else-if / v-else |
條件渲染 | <p v-if="isLogin">已登入</p> |
v-show |
顯示/隱藏(使用 CSS) | <div v-show="visible">內容</div> |
v-for |
迭代陣列或物件 | <li v-for="item in list" :key="item.id">{{ item.text }}</li> |
v-model |
雙向綁定表單元素 | <input v-model="msg" /> |
2.1 v-bind 與縮寫 :
v-bind 可以把 JavaScript 表達式的值綁定到任意屬性上,常用於 動態 class、style、src 等。
<template>
<button :class="{ active: isActive }" :style="{ color: btnColor }">
點我
</button>
</template>
<script setup>
import { ref } from 'vue'
const isActive = ref(true)
const btnColor = ref('white')
</script>
小技巧:若要一次綁定多個屬性,可使用物件語法
v-bind="{ href, target }"。
2.2 事件綁定 v-on(@)
Vue 會自動把事件的 event 參數傳入,若不需要可以省略。
<template>
<input @keyup.enter="submit" placeholder="按 Enter 送出" />
</template>
<script setup>
function submit(event) {
console.log('送出內容:', event.target.value)
}
</script>
2.3 條件渲染 v-if / v-else-if / v-else
v-if 會在條件改變時銷毀或重新建立 DOM,適合較大或昂貴的區塊;v-show 只改變 display,適合頻繁切換的小區塊。
<template>
<p v-if="status === 'loading'">載入中…</p>
<p v-else-if="status === 'error'">發生錯誤!</p>
<p v-else>資料已載入。</p>
</template>
<script setup>
import { ref } from 'vue'
const status = ref('loading') // loading / error / success
</script>
2.4 迭代渲染 v-for
v-for 必須提供唯一的 key,這對 Vue 的 diff 演算法至關重要。
<template>
<ul>
<li v-for="todo in todos" :key="todo.id">
<input type="checkbox" v-model="todo.done" />
<span :class="{ done: todo.done }">{{ todo.text }}</span>
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const todos = ref([
{ id: 1, text: '學習 Vue', done: false },
{ id: 2, text: '寫部落格', done: true },
])
</script>
<style scoped>
.done { text-decoration: line-through; }
</style>
2.5 雙向綁定 v-model
v-model 會自動把表單值與資料屬性同步,支援 修飾符(.lazy、.number、.trim)以控制更新時機與類型。
<template>
<input v-model.trim="username" placeholder="輸入使用者名稱" />
<input type="number" v-model.number="age" placeholder="年齡" />
<p>您好,{{ username }},您 {{ age }} 歲。</p>
</template>
<script setup>
import { ref } from 'vue'
const username = ref('')
const age = ref(null)
</script>
3. 動態組件與 v-slot(插槽)
在大型應用中,我們常需要 在父層傳遞 UI 結構,此時可以使用 <component :is="..."> 搭配 具名插槽。
<template>
<!-- 父層 -->
<DynamicCard :is="currentCard">
<template #header>
<h2>{{ title }}</h2>
</template>
<template #default>
<p>卡片內容由父層決定。</p>
</template>
</DynamicCard>
</template>
<script setup>
import { ref } from 'vue'
import DynamicCard from './DynamicCard.vue'
const currentCard = ref('InfoCard')
const title = ref('最新消息')
</script>
<!-- DynamicCard.vue -->
<template>
<component :is="type" class="card">
<slot name="header"></slot>
<slot></slot>
</component>
</template>
<script setup>
import { defineProps } from 'vue'
const props = defineProps({
is: { type: String, required: true }
})
const type = props.is
</script>
重點:
v-slot允許把 資料 從子組件傳回父層(slot-scope),在 Vue 3 中已改為v-slot="{ data }"的語法。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
忘記加 key |
v-for 沒有唯一鍵會導致渲染錯位或效能下降。 |
為每筆資料提供穩定且唯一的 id,盡量避免使用索引作為 key。 |
在 {{ }} 中使用語句 |
只能放表達式,語句會拋錯。 | 把複雜邏輯搬到 computed 或 methods 中,模板只保留簡單表達式。 |
過度使用 v-if |
大量 v-if 會頻繁掛載/銷毀 DOM,影響效能。 |
若元素頻繁切換,改用 v-show;若條件只在初始化決定,仍使用 v-if。 |
| 雙向綁定過度 | v-model 直接修改資料,可能導致不可預期的副作用。 |
僅在表單輸入與 UI 同步時使用,其他情況使用單向綁定加事件處理。 |
| 插值過長 | 長度超過 2000+ 字元的插值會降低可讀性。 | 把大型文字或 HTML 片段抽離成子組件或使用 v-html(注意 XSS)。 |
最佳實踐
- 保持模板簡潔:所有業務邏輯放在
setup()、computed或store中,模板只負責渲染。 - 使用
script setup:減少樣板程式碼,提升可讀性。 - 分離樣式:使用
<style scoped>或 CSS Modules,避免樣式洩漏。 - 預先定義類型:在 TypeScript 專案中,為 props、data、emit 定義介面,提升開發體驗。
- 善用
v-memo(Vue 3.3+):對不常變動的區塊使用v-memo,減少不必要的重新渲染。
實際應用場景
表單驗證與即時回饋
使用v-model兩端綁定表單欄位,配合computed判斷錯誤訊息,透過v-if即時顯示驗證結果。動態列表與分頁
v-for搭配key渲染 API 回傳的商品清單,使用v-show切換「載入中」與「無資料」狀態,提升使用者體驗。可重用卡片元件
透過<component :is="...">與具名插槽v-slot,讓同一個卡片框架支援多種內容(圖表、文字、表格),降低重複程式碼。條件式功能切換
在權限管理系統中,以v-if控制不同角色的功能按鈕,確保 UI 與後端權限保持一致。動畫與過渡
結合<transition>、v-show以及 CSS 動畫,實作彈出視窗、下拉選單等互動效果。
總結
模板語法是 Vue 3 最核心的特性之一,簡潔的插值、強大的指令以及靈活的插槽 讓開發者能以宣告式的方式快速構建 UI。掌握以下要點,就能在實務專案裡寫出 可讀、可維護且效能良好 的程式碼:
- 使用
{{ }}只放簡單表達式,複雜邏輯移至computed/methods。 v-bind、v-on的縮寫:、@能大幅減少樣板。- 針對不同需求選擇
v-if(掛載/銷毀)或v-show(CSS 隱藏)。 v-for必須配合唯一key,避免渲染錯位。v-model方便表單雙向綁定,但要注意過度使用的副作用。- 動態組件與插槽提供高度可組合的 UI 結構,適合大型專案的模組化開發。
只要遵循以上最佳實踐,你就能在 Vue 3 的模板語法世界裡,快速開發出功能完整且具備良好使用者體驗的 Web 應用。祝你寫程式開心,專案順利!