本文 AI 產出,尚未審核

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. 基本語法規則

  1. 單向綁定:{{ data }} 只會把資料寫入 DOM,不會把使用者輸入寫回資料。
  2. 自動 HTML 逃脫:插值的內容會自動轉義,防止 XSS 攻擊。若要輸出原始 HTML,需改用 v-html。
  3. 支援過濾器 (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 控制顯示

最佳實踐

  1. 保持 Mustache 為「純展示」:所有計算、條件判斷、字串處理均放在 computed 或 methods 中。
  2. 使用 ref / reactive:確保資料具備 響應式,否則插值不會自動更新。
  3. 加入 :key:在 v-for 搭配 Mustache 時,務必提供唯一鍵值,避免列表重排導致 UI 異常。
  4. 避免 XSS:除非確信內容安全,千萬不要在 Mustache 中直接插入使用者輸入的 HTML。
  5. 統一風格:在團隊內部規範「所有 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 的模板語法將持續為你提供高效、可讀且易於維護的開發體驗。祝你寫程式愉快! 🚀