Vue3 教學:模板語法 – Mustache ({{ variable }})
簡介
在 Vue3 中,模板 (Template) 是與資料互動的第一層介面。大多數新手在看到 Vue 組件的 .vue 檔時,第一眼會注意到 {{ }} 這對大括號——也就是 Mustache 語法。它看似簡單,卻是 Vue 資料綁定 (Data Binding) 的核心入口,負責把 JavaScript 中的資料「渲染」到 HTML,讓畫面隨資料變化而即時更新。
掌握 Mustache 語法不只讓你能快速顯示文字、數字或計算結果,更是深入了解 響應式系統、生命週期 與 組件溝通 的基礎。若能正確運用,開發者可以在不寫任何 DOM 操作程式碼的情況下,建立互動且易於維護的 UI。
本篇文章將從 概念、實作範例、常見陷阱、最佳實踐 以及 實務應用 四個面向,完整說明 Mustache 語法在 Vue3 中的使用方式,幫助初學者快速上手,也讓中級開發者進一步優化寫法。
核心概念
1. Mustache 為何叫「插值」
Mustache 本質上是一種 文字插值 (Interpolation),語法為 {{ expression }},其中 expression 必須是一個 單一的 JavaScript 表達式,且 只能返回字串、數字、布林或可被 Vue 自動轉換的值。Vue 會在組件建立時解析這段表達式,將結果插入對應的 DOM 節點;之後若相關的 reactive 資料發生變化,Vue 會自動重新渲染。
⚡ 重點:Mustache 不支援 陳述式 (如
if、for)、函式宣告或多行程式碼;若需要複雜邏輯,請改用 computed、methods 或 v‑if / v‑for。
2. 何時使用 Mustache
| 場景 | 建議使用 | 替代方案 |
|---|---|---|
| 顯示純文字、數字、布林值 | ✅ Mustache | — |
| 需要 HTML 標籤或屬性動態化 | ❌ Mustache → v-html、v-bind |
— |
| 多條件或迴圈渲染 | ❌ Mustache → v-if、v-for |
— |
| 需要執行方法或計算結果 | ✅ 在 computed 中先處理,再用 Mustache 顯示 |
— |
3. 基本語法規則
- 單向綁定:
{{ data }}只會把資料寫入 DOM,不會把使用者輸入寫回資料。 - 自動 HTML 逃脫:插值的內容會自動轉義,防止 XSS 攻擊。若要輸出原始 HTML,需改用
v-html。 - 支援過濾器 (Vue 3 已棄用):舊版 Vue2 常見
{{ msg | capitalize }},在 Vue3 中改用 computed 或 methods。
程式碼範例
以下範例均以 單檔組件 (Single File Component) 為基礎,使用 <script setup> 語法,讓程式碼更簡潔。
範例 1:顯示基本資料
<template>
<h2>使用者資訊</h2>
<!-- Mustache 直接插入文字 -->
<p>姓名:{{ name }}</p>
<p>年齡:{{ age }}</p>
<p>已驗證:{{ isVerified ? '是' : '否' }}</p>
</template>
<script setup>
import { ref } from 'vue'
const name = ref('陳小明')
const age = ref(28)
const isVerified = ref(true)
</script>
說明:
{{ isVerified ? '是' : '否' }}為單行三元運算子,仍屬於「單一表達式」的範疇,符合 Mustache 的限制。
範例 2:使用 computed 處理衍生資料
<template>
<h3>商品資訊</h3>
<p>原價:${{ price }}</p>
<p>折扣後價格:${{ discountedPrice }}</p>
<p>顯示訊息:{{ priceMessage }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
const price = ref(1200)
const discount = ref(0.15)
// 計算折扣後的價格
const discountedPrice = computed(() => {
return Math.round(price.value * (1 - discount.value))
})
// 產生需要顯示的訊息,使用 computed 讓 Mustache 只負責插值
const priceMessage = computed(() => {
return discountedPrice.value < 1000
? '價格已低於 1000 元,快下單!'
: '仍在原價區間。'
})
</script>
說明:將較複雜的邏輯放入
computed,保持 Mustache 只負責「顯示」而不做運算,提升可讀性與效能。
範例 3:多層物件與陣列的插值
<template>
<h3>待辦清單</h3>
<ul>
<!-- 直接插入陣列元素的屬性 -->
<li v-for="(item, idx) in todoList" :key="idx">
{{ idx + 1 }}. {{ item.title }} - {{ item.done ? '完成' : '未完成' }}
</li>
</ul>
</template>
<script setup>
import { reactive } from 'vue'
const todoList = reactive([
{ title: '寫教學文章', done: true },
{ title: '練習 Vue3', done: false },
{ title: '閱讀技術文件', done: false }
])
</script>
說明:
v-for本身不是 Mustache,但在迭代時仍可在{{ }}中使用 陣列索引、物件屬性,只要保持為單行表達式即可。
範例 4:字串拼接與模板字面量
<template>
<p>歡迎訊息:{{ welcomeMessage }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
const user = ref({ name: '林志玲', role: '管理員' })
// 使用模板字面量組合字串
const welcomeMessage = computed(() => {
return `嗨 ${user.value.name},您是 ${user.value.role}。`
})
</script>
說明:即使在
computed中使用 ES6 的模板字面量,最後仍以單一值回傳給 Mustache,符合語法規範。
範例 5:自訂全域過濾器(Vue3 推薦做法)
<template>
<p>大寫姓名:{{ upperName }}</p>
</template>
<script setup>
import { ref, computed } from 'vue'
// 直接在 computed 中完成過濾功能
const name = ref('王大明')
const upperName = computed(() => name.value.toUpperCase())
</script>
說明:Vue3 已移除過濾器(filter)功能,建議以 computed 或 method 取代,以保持程式碼一致性與型別安全。
常見陷阱與最佳實踐
| 陷阱 | 可能的結果 | 解決方法 |
|---|---|---|
| 插入 HTML 標籤 | 文字被自動轉義,顯示 <b>文字</b> 而非粗體 |
使用 v-html(僅限可信內容)或在 computed 中產生安全的 HTML |
| 在 Mustache 內寫多行程式 | 解析錯誤、編譯失敗 | 把程式碼抽到 computed、methods,只在 Mustache 中放單行表達式 |
| 使用非 reactive 變數 | 資料變更不會觸發重新渲染 | 使用 ref、reactive、computed,或在 setup 中返回普通變數給模板 |
| 在迴圈中直接改變陣列 | 可能導致渲染錯位或效能下降 | 使用 v-for 搭配 :key,並在資料層面使用 push、splice 等 Vue 支援的變更方式 |
| 過度使用 Mustache 進行條件判斷 | 可讀性差、維護困難 | 把條件邏輯搬到 computed,或改用 v-if / v-show 控制顯示 |
最佳實踐
- 保持 Mustache 為「純展示」:所有計算、條件判斷、字串處理均放在
computed或methods中。 - 使用
ref/reactive:確保資料具備 響應式,否則插值不會自動更新。 - 加入
:key:在v-for搭配 Mustache 時,務必提供唯一鍵值,避免列表重排導致 UI 異常。 - 避免 XSS:除非確信內容安全,千萬不要在 Mustache 中直接插入使用者輸入的 HTML。
- 統一風格:在團隊內部規範「所有 Mustache 表達式僅允許單行、無副作用」的寫法,提升代碼一致性。
實際應用場景
1. 儀表板 (Dashboard) 中的即時指標
在金融或監控系統的儀表板,常需要即時顯示 數字、百分比、狀態文字。透過 Mustache 搭配 ref、computed,可以在資料變動時自動刷新 UI,無需手動操作 DOM。
<template>
<div class="stats">
<p>CPU 使用率:{{ cpuUsage }}%</p>
<p>記憶體剩餘:{{ freeMemory }} MB</p>
<p>系統狀態:{{ systemStatus }}</p>
</div>
</template>
<script setup>
import { ref, computed, onMounted } from 'vue'
const cpuUsage = ref(0)
const freeMemory = ref(0)
const systemStatus = computed(() => {
if (cpuUsage.value > 80) return '高負載'
if (cpuUsage.value > 50) return '正常'
return '閒置'
})
// 模擬每秒更新一次的資料來源
onMounted(() => {
setInterval(() => {
cpuUsage.value = Math.round(Math.random() * 100)
freeMemory.value = Math.round(8000 + Math.random() * 2000)
}, 1000)
})
</script>
2. 多語言 (i18n) 文字插值
使用 vue-i18n 時,常會在模板中直接插入翻譯字串。Mustache 能簡潔呈現 動態佔位符。
<template>
<p>{{ $t('welcome', { name: userName }) }}</p>
</template>
<script setup>
import { ref } from 'vue'
const userName = ref('張惠妹')
</script>
註:
$t返回的字串已經完成插值,Mustache 僅負責顯示。
3. 表單回饋訊息
在表單驗證成功或失敗時,常需要顯示即時的提示文字。利用 ref 追蹤錯誤訊息,再以 Mustache 渲染。
<template>
<form @submit.prevent="handleSubmit">
<input v-model="email" type="email" placeholder="請輸入 Email" />
<p class="error">{{ emailError }}</p>
<button type="submit">送出</button>
</form>
</template>
<script setup>
import { ref } from 'vue'
const email = ref('')
const emailError = ref('')
function handleSubmit() {
if (!email.value.includes('@')) {
emailError.value = '請輸入有效的 Email 地址!'
} else {
emailError.value = ''
// 送出資料...
}
}
</script>
總結
Mustache ({{ variable }}) 是 Vue3 中最直觀、最常見的 文字插值 方式。它的核心概念是 單向、響應式、HTML 逃脫,讓開發者只需關注資料本身,而不必擔心 DOM 更新的細節。
- 保持單行、純展示:將所有邏輯搬到
computed或methods,讓模板保持乾淨。 - 使用
ref/reactive:確保資料具備響應式,才能驅動 Mustache 自動重繪。 - 注意安全:除非內容可信,切勿使用 Mustache 輸出未過濾的 HTML,以免產生 XSS。
- 遵循最佳實踐:結合
v-if、v-for、v-bind等指令,讓 UI 更具彈性與可維護性。
透過本文的概念解說與多個實務範例,你應該已經能在 Vue3 專案中自如使用 Mustache,從簡單的文字顯示到即時儀表板、國際化與表單回饋,都能快速完成。未來在面對更複雜的 UI 需求時,只要遵循「資料驅動、模板純粹」的原則,Vue3 的模板語法將持續為你提供高效、可讀且易於維護的開發體驗。祝你寫程式愉快! 🚀