Vue3 教學:指令(Directives)— v-cloak 與 v-pre
簡介
在 Vue3 中,指令是與 HTML 標籤 互動的核心機制,允許開發者在模板上掛載特殊行為。除了常見的 v-if、v-show、v-model,還有兩個較少被提及、卻在 首次渲染 時發揮關鍵作用的指令:v-cloak 與 v-pre。
v-cloak用來 防止閃爍的原始 Mustache 標記({{ }})在 Vue 完成掛載前被瀏覽器渲染。v-pre則是 告訴 Vue 跳過該區塊的編譯,讓純文字或第三方模板語言可以安全共存。
這兩個指令不會改變資料或 DOM 結構,但在 提升使用者體驗、降低不必要的編譯成本 方面相當重要,特別是對於 SEO、SSR 或需要與其他前端框架混用的專案。
核心概念
1. v-cloak:隱藏未編譯的模板
原理
v-cloak 本身不會產生任何功能,它只是一個 CSS 標記。當 Vue 完成編譯並掛載後,會自動移除該屬性。只要在樣式中將 [v-cloak] 設為 display:none,就能避免使用者在頁面加載時看到 {{ message }} 之類的原始字串。
使用方式
<!-- index.html -->
<style>
[v-cloak] { display: none; }
</style>
<div id="app" v-cloak>
{{ message }}
</div>
// main.js
import { createApp } from 'vue';
import App from './App.vue';
createApp(App).mount('#app');
重點:
v-cloak必須在 Vue 實例掛載之前 生效,因此樣式宣告要放在最上層(如<head>)或在外部 CSS 中提前載入。
2. v-pre:跳過編譯的區塊
原理
v-pre 告訴 Vue 不對該元素及其子孫執行任何指令解析或 Mustache 替換。這對於以下情況特別有用:
- 顯示原始 Mustache 語法(例如教學文件)。
- 與其他模板引擎(如 Handlebars、EJS)共存,避免衝突。
- 大量靜態內容,可減少 Vue 的編譯成本,提高效能。
使用方式
<!-- 顯示 Mustache 語法的教學範例 -->
<pre v-pre>
{{ user.name }} // 這裡不會被 Vue 解析
</pre>
<!-- 與 Handlebars 共存 -->
<div id="handlebars-template">
{{!-- Handlebars 使用 {{}},若不加 v-pre 會被 Vue 攔截 --}}
{{#if condition}}
<p>Hello Handlebars!</p>
{{/if}}
</div>
<div id="app" v-pre>
<!-- Vue 完全不會編譯這裡的內容 -->
{{ vueIgnored }}
</div>
3. v-cloak 與 v-pre 的差異
| 指令 | 作用 | 是否編譯子元素 | 典型使用情境 |
|---|---|---|---|
v-cloak |
隱藏未編譯的模板,掛載後自動移除 | 會編譯子元素 | 防止閃爍的 {{}}、首次渲染時的佈局抖動 |
v-pre |
完全跳過編譯,保留原始文字 | 不會編譯任何子孫 | 顯示教學範例、與其他模板引擎共存、提升靜態區塊效能 |
程式碼範例
範例 1:基本 v-cloak 防止閃爍
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>v-cloak 範例</title>
<style>
[v-cloak] { display: none; } /* 隱藏未編譯的內容 */
</style>
</head>
<body>
<div id="app" v-cloak>
<h1>{{ title }}</h1>
<p>載入中…</p>
</div>
<script type="module">
import { createApp } from 'vue';
createApp({
data() {
return { title: 'Vue3 與 v-cloak' };
}
}).mount('#app');
</script>
</body>
</html>
說明:在 Vue 完成掛載前,[v-cloak] 讓整個區塊隱藏,使用者不會看到 {{ title }}。
範例 2:v-pre 用於教學文件
<template>
<section>
<h2>Vue Mustache 語法說明</h2>
<pre v-pre>
{{ message }} // 這段文字會原樣顯示,不會被 Vue 解析
</pre>
</section>
</template>
<script>
export default {
data() {
return { message: 'Hello Vue!' };
}
};
</script>
說明:<pre> 內的 Mustache 會直接呈現在畫面上,適合寫教學手冊或範例程式碼。
範例 3:與 Handlebars 共存的混合模板
<!-- index.html -->
<div id="handlebars-root">
{{!-- Handlebars 變數 --}}
{{#each items}}
<li>{{this}}</li>
{{/each}}
</div>
<div id="vue-app" v-pre>
<!-- Vue 完全不會觸碰這裡,避免與 Handlebars 的 {{}} 衝突 -->
{{ vueIgnored }}
</div>
<script src="https://cdn.jsdelivr.net/npm/handlebars@latest/dist/handlebars.min.js"></script>
<script src="https://unpkg.com/vue@3"></script>
<script>
// Handlebars 渲染
const source = document.getElementById('handlebars-root').innerHTML;
const template = Handlebars.compile(source);
const html = template({ items: ['A', 'B', 'C'] });
document.getElementById('handlebars-root').innerHTML = html;
// Vue 初始化(不會編譯 v-pre 區塊)
Vue.createApp({}).mount('#vue-app');
</script>
說明:v-pre 確保 Vue 不會把 Handlebars 的 {{}} 當成自己的 Mustache,兩者可以和平共存。
範例 4:大量靜態表格使用 v-pre 提升效能
<table v-pre>
<thead>
<tr><th>編號</th><th>說明</th></tr>
</thead>
<tbody>
<!-- 這裡是從後端直接注入的靜態 HTML,無需 Vue 解析 -->
<tr><td>1</td><td>固定說明文字</td></tr>
<tr><td>2</td><td>固定說明文字</td></tr>
<!-- ... 1000 筆資料 -->
</tbody>
</table>
說明:對於數千筆不會變動的資料表,使用 v-pre 可避免 Vue 逐筆編譯,提高首次渲染速度。
範例 5:結合 v-cloak 與 v-pre 的實務案例
<!DOCTYPE html>
<html lang="zh-Hant">
<head>
<meta charset="UTF-8">
<title>混合範例</title>
<style>
[v-cloak] { visibility: hidden; } /* 隱藏但保留布局,避免跳動 */
</style>
</head>
<body>
<div id="app" v-cloak>
<h1>{{ pageTitle }}</h1>
<!-- 教學碼區塊,使用 v-pre -->
<pre v-pre>
{{ example }} // 這裡不會被 Vue 解析
</pre>
</div>
<script type="module">
import { createApp } from 'vue';
createApp({
data() {
return {
pageTitle: 'Vue3 v-cloak & v-pre 混合使用',
example: 'Hello World'
};
}
}).mount('#app');
</script>
</body>
</html>
說明:v-cloak 確保整個 #app 在 Vue 完成掛載前保持隱蔽,v-pre 則讓教學區塊保持原樣。兩者同時使用,可在同一頁面中兼顧 避免閃爍 與 保留原始文字。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方案 / Best Practice |
|---|---|---|
忘記加入 [v-cloak] CSS |
v-cloak 只是一個屬性,若沒有相對的樣式,使用者仍會看到 {{}}。 |
在全局樣式或 <head> 中加入 [v-cloak] { display:none; }(或 visibility:hidden) |
把 v-pre 用在需要互動的區塊 |
v-pre 會阻止所有 Vue 解析,導致 v-on、v-model 等指令失效。 |
僅在純展示或靜態內容使用;若需要互動,改用普通模板或 v-if 包裹 |
在 SSR 中使用 v-cloak |
伺服器端渲染已經產生完整 HTML,v-cloak 仍會隱藏內容,造成空白。 |
在 SSR 專案中,可在客戶端掛載前移除 v-cloak,或直接使用 v-if 控制渲染時機 |
| 樣式優先級不足 | 若外部 CSS 或框架(如 Bootstrap)對 [v-cloak] 有更高優先權,隱藏效果會失效。 |
使用更具體的選擇器或 !important(盡量避免)確保隱藏樣式生效 |
誤用 v-pre 產生 XSS |
跳過編譯意味著 Vue 不會對內容做任何過濾,若直接插入不可信的 HTML,可能造成 XSS。 | 僅在確保內容安全的情況下使用 v-pre,或搭配 v-html 前先做 sanitization |
最佳實踐總結:
- 全局宣告
[v-cloak],確保所有頁面都有防閃爍保護。 - 僅在必要時使用
v-pre,避免過度跳過編譯導致功能缺失。 - 配合開發工具(Vue Devtools),檢查
v-cloak是否已被正確移除。 - 在 CI/CD 流程或單元測試中加入檢查,確保不會因遺漏
v-cloak而產生 UI 問題。
實際應用場景
多語系網站的 SEO 首頁
需要在伺服器渲染(SSR)後立即呈現完整內容,避免搜尋引擎抓到{{}}。在客戶端使用v-cloak隱藏過渡階段,確保首次渲染的純文字不被曝光。教學平台或文件站
說明 Vue 語法的教學頁面常會示範 Mustache 語法本身,使用v-pre可以直接顯示{{ variable }}而不被解析。與第三方模板引擎混合
大型企業系統往往同時使用 Handlebars、Mustache、EJS 等,v-pre能讓 Vue 與這些引擎共存,避免因指令衝突導致渲染錯誤。大量靜態資料的報表
從後端一次性注入千筆不會變動的表格資料,使用v-pre可省去 Vue 的編譯時間,提升頁面載入速度。漸進式增強(Progressive Enhancement)
在僅支援純 HTML 的環境下(如舊版瀏覽器),v-pre可保證內容仍可閱讀;而在支援 JavaScript 的環境中,透過v-cloak隱藏過渡,提供更佳使用者體驗。
總結
v-cloak 與 v-pre 雖然是 Vue3 中相對簡單的兩個指令,卻在 首次渲染的穩定性、模板衝突的解決 以及 效能優化 上扮演關鍵角色。
v-cloak:配合全局 CSS,防止 Mustache 標記閃爍,適用於所有需要平滑首次載入的 Vue 應用。v-pre:讓 Vue 完全跳過編譯,適合展示教學範例、與其他模板引擎共存或處理大量靜態內容。
在實務開發中,只要遵循正確的使用時機、避免過度使用,並配合最佳實踐(如全局樣式、測試驗證),就能讓應用在 使用者體驗 與 效能 上都得到顯著提升。希望本篇教學能幫助你在 Vue3 專案中靈活運用 v-cloak 與 v-pre,打造更穩定、易維護的前端介面。祝開發順利!