Vue3 教學 – 模板語法(Template Syntax)
主題:v-show 顯示 / 隱藏
簡介
在 Vue3 的模板語法中,條件渲染是最常見的需求之一。開發者往往需要根據狀態動態地顯示或隱藏某段 UI,這時就會用到兩個指令:v-if 與 v-show。雖然兩者的目的相同——控制元素的可見性,但底層實作與使用時機卻大不相同。
v-show 透過 CSS 的 display 屬性 來切換元素的顯示狀態,不會把元素從 DOM 中移除。因此在頻繁切換顯示/隱藏的情境下,v-show 的效能往往優於 v-if。本篇文章將深入探討 v-show 的工作原理、使用方式、常見陷阱與最佳實踐,並提供多個實務範例,幫助你在 Vue3 專案中正確且有效地運用這個指令。
核心概念
1. v-show 的基本語法
<div v-show="isVisible">這段文字會根據 isVisible 顯示或隱藏</div>
isVisible必須是 布林值(true/false)或能夠被轉換成布林值的表達式。- 當
isVisible為true時,Vue 會在元素上設定display: ''(即恢復原本的顯示方式)。 - 當
isVisible為false時,Vue 會設定display: none,使元素在畫面上隱藏,但仍保留在 DOM 中。
重點:
v-show不會觸發 Vue 的虛擬 DOM 重排,只是單純改變 CSS,故適合頻繁切換的場景。
2. 與 v-if 的差異
| 特性 | v-if |
v-show |
|---|---|---|
| 渲染時機 | 只在條件為 true 時才渲染,條件改變會 掛載 / 卸載 元素 |
初始渲染時就掛載,之後僅切換 display |
| DOM 變化 | 會 新增 / 移除 DOM 節點 | 保持 DOM,僅改變樣式 |
| 效能 | 初始渲染較慢,但切換時不會產生重排 | 初始渲染快,但每次切換都會觸發 CSS 重排 |
| 使用情境 | 條件較少變動、需要大量資源的子組件 | 需要頻繁顯示/隱藏、子組件渲染成本低 |
建議:如果元素的顯示狀態在 短時間內頻繁變化,優先考慮
v-show;若條件較為固定且子組件較重,則使用v-if以減少不必要的渲染。
3. v-show 的底層實作
當 Vue 解析到 v-show 時,會在編譯階段為目標元素生成一段 runtime directive。這段指令在掛載(mount)階段會檢查綁定值,並在 更新(update)階段根據新值調整 style.display:
function toggle(el, value) {
el.style.display = value ? '' : 'none';
}
因此,只要 value(即綁定的表達式)改變,Vue 只需要一次簡單的 DOM 操作,不會觸發子樹的重新渲染。
4. 多個 v-show 的疊加
在同一元素上使用多個 v-show(例如在父子組件都加上 v-show)時,最終的 display 屬性會受到 最內層指令 的控制。若任一層的條件為 false,元素將最終呈現 display: none。這在 層層控制可見性 時相當有用:
<!-- 父層控制 -->
<div v-show="parentVisible">
<!-- 子層再做一次控制 -->
<span v-show="childVisible">子元素</span>
</div>
程式碼範例
以下示範 5 個常見且實用的 v-show 用法,從最基礎到稍微進階的情境都有涵蓋。每段程式碼皆附上說明註解,方便讀者快速理解。
範例 1:最簡單的布林控制
<template>
<button @click="show = !show">
{{ show ? '隱藏' : '顯示' }} 文字
</button>
<p v-show="show">
這段文字會根據 show 的值顯示或隱藏。
</p>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(true) // 初始為 true,文字顯示
</script>
說明:
show為ref,點擊按鈕會切換布林值,v-show立即改變display。
範例 2:結合計算屬性(computed)
<template>
<input type="text" v-model="keyword" placeholder="輸入關鍵字" />
<div v-show="hasResult">
搜尋結果顯示在這裡…
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const keyword = ref('')
const hasResult = computed(() => {
// 只要關鍵字長度大於 2,就視為有搜尋結果
return keyword.value.length > 2
})
</script>
說明:使用
computed讓條件判斷更具可讀性,且在keyword改變時自動重新計算。
範例 3:在表格中切換行的可見性
<template>
<table class="table-auto border-collapse w-full">
<thead>
<tr class="bg-gray-100">
<th class="p-2">#</th>
<th class="p-2">名稱</th>
<th class="p-2">狀態</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id">
<td class="p-2">{{ item.id }}</td>
<td class="p-2">{{ item.name }}</td>
<td class="p-2">
<button @click="item.visible = !item.visible">
{{ item.visible ? '隱藏' : '顯示' }}
</button>
</td>
</tr>
<!-- 詳細資訊列,依據 item.visible 控制顯示 -->
<tr v-for="item in items" :key="'detail-' + item.id" v-show="item.visible" class="bg-gray-50">
<td colspan="3" class="p-2">
這是 {{ item.name }} 的詳細說明…(可以放任何 HTML)
</td>
</tr>
</tbody>
</table>
</template>
<script setup>
import { reactive } from 'vue'
const items = reactive([
{ id: 1, name: 'Apple', visible: false },
{ id: 2, name: 'Banana', visible: false },
{ id: 3, name: 'Cherry', visible: false },
])
</script>
說明:使用
v-show在同一tbody中切換「詳細資訊」列的顯示,避免因v-if產生額外的 DOM 重排。
範例 4:結合過渡(transition)效果
v-show 與 <transition> 搭配時,需要使用 appear 或自訂 CSS 來控制過渡。以下示範淡入淡出的動畫:
<template>
<button @click="open = !open">
{{ open ? '關閉' : '開啟' }} 抽屜
</button>
<transition name="fade">
<div v-show="open" class="drawer">
<p>這是一段抽屜內容,使用 fade 轉場。</p>
</div>
</transition>
</template>
<script setup>
import { ref } from 'vue'
const open = ref(false)
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.3s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
.drawer {
padding: 1rem;
background: #f5f5f5;
border: 1px solid #ddd;
margin-top: 0.5rem;
}
</style>
說明:
v-show本身不會觸發過渡,但配合<transition>可以在display變化前後加上 CSS 動畫,提供更好的使用者體驗。
範例 5:在組件內部使用 v-show 控制插槽內容
<!-- Modal.vue -->
<template>
<div class="modal-overlay" v-show="visible" @click.self="close">
<div class="modal-content">
<slot></slot>
<button @click="close" class="mt-2">關閉</button>
</div>
</div>
</template>
<script setup>
import { defineProps, defineEmits } from 'vue'
const props = defineProps({
modelValue: { type: Boolean, default: false }
})
const emit = defineEmits(['update:modelValue'])
const visible = computed({
get: () => props.modelValue,
set: (val) => emit('update:modelValue', val)
})
function close() {
visible.value = false
}
</script>
<style scoped>
.modal-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,0.5);
display: flex;
align-items: center;
justify-content: center;
}
.modal-content {
background: white;
padding: 1.5rem;
border-radius: 0.5rem;
}
</style>
<!-- App.vue -->
<template>
<button @click="showModal = true">開啟 Modal</button>
<Modal v-model="showModal">
<h2 class="text-xl">這是插槽內容</h2>
<p>使用 v-show 控制整個 Modal 的顯示與隱藏。</p>
</Modal>
</template>
<script setup>
import { ref } from 'vue'
import Modal from './components/Modal.vue'
const showModal = ref(false)
</script>
說明:在自訂 Modal 組件中,
v-show控制整個遮罩層的可見性,配合v-model(modelValue)實現雙向綁定,使外部使用者可以輕鬆開關 Modal。
常見陷阱與最佳實踐
| 陷阱 | 可能的問題 | 解法或最佳實踐 |
|---|---|---|
| 誤用於大型子組件 | 子組件渲染成本高,頻繁切換 display 仍會保留大量記憶體、事件監聽等。 |
若子組件較重,改用 v-if 讓 Vue 在不需要時 卸載。 |
與 CSS display 衝突 |
直接在樣式表中設定 display: block 或 inline,但 v-show 會覆寫為 none,導致意外行為。 |
使用 CSS class 來設定顯示樣式,讓 v-show 只負責 none/'' 切換。 |
| 過渡效果失效 | 直接在 v-show 元素上寫 transition,但 Vue 在切換 display 前不觸發過渡。 |
必須把元素包在 <transition> 中,或自行在 v-show 前後加入動畫類別。 |
多層 v-show 造成維護困難 |
父子層都使用 v-show,條件分散,難以追蹤最終可見性。 |
集中管理:將可見性狀態提升至共同父層,或使用 computed 產生單一布林值。 |
| 在 SSR(Server‑Side Rendering)中誤用 | SSR 預渲染時,v-show 仍會產生元素,若不希望在首屏渲染出來,會造成 FOUC(Flash of Unstyled Content)。 |
結合 v-if 或在 mounted 後再切換 v-show,避免首屏顯示不必要的內容。 |
最佳實踐小結
- 頻繁切換 → 使用
v-show。 - 初始渲染成本高 → 使用
v-if。 - 需要過渡動畫 → 搭配
<transition>,或自行控制 CSS。 - 避免 CSS 衝突 → 只在樣式表中設定
display的 預設,讓v-show處理none。 - 狀態集中 → 把可見性布林值提升至最近的共同父層,避免多層
v-show互相干擾。
實際應用場景
| 場景 | 為何選擇 v-show |
|---|---|
| Tab 切換 | 切換 Tab 時只改變內容區塊的可見性,保持 DOM 結構,避免重新渲染子組件。 |
| 下拉選單 / 手風琴 | 使用者點擊展開/收合時頻繁觸發,v-show 能即時切換 display,提供流暢體驗。 |
| 載入中遮罩 | 只需要顯示或隱藏遮罩層,不需要重新渲染遮罩內部的結構。 |
| 表格行的詳細資訊 | 如前面的範例,點擊展開行的細節,保持表格的排版不變。 |
| Modal / Dialog | 透過 v-show 控制整個 Modal 的顯示,配合過渡可得到平滑的開關效果。 |
| 權限控制的 UI | 某些功能只對特定使用者顯示,切換權限時即時隱藏/顯示相關按鈕,避免重新渲染整個頁面。 |
總結
v-show 是 Vue3 中 輕量級的條件渲染指令,它透過改變元素的 display 屬性來達成顯示與隱藏,不會移除 DOM。這使得它在需要頻繁切換可見性的 UI(如 Tab、手風琴、Modal)上表現尤為出色。
在使用時,務必留意以下要點:
- 頻繁切換 →
v-show;渲染成本高 →v-if。 - 若要加上過渡效果,請配合
<transition>。 - 避免與直接設定的 CSS
display發生衝突,建議使用 class 方式統一管理樣式。 - 在大型子組件或 SSR 場景中,評估是否真的需要保留在 DOM,必要時改用
v-if。
掌握了 v-show 的原理與最佳實踐,你就能在 Vue3 專案中靈活地控制 UI 可見性,提升使用者體驗與程式效能。祝你開發順利,寫出更佳的 Vue 應用!