v-if 與 v-show 的區別
v-if 和 v-show 都能控制元素是否顯示,但它們的底層行為完全不同。面試裡如果只回答「v-if 是條件渲染,v-show 是 display none」,通常還不夠。
一句話回答:v-if 會真正建立或銷毀 DOM 與元件;v-show 會保留 DOM,只透過 CSS 的 display 控制顯示與隱藏。
一、 必考觀念
1. v-if 是條件渲染
v-if 條件為 false 時,對應的 DOM 不會被建立。
<template>
<UserPanel v-if="isLogin" />
</template>如果 isLogin 是 false,UserPanel 不會掛載。當 isLogin 變成 true 時,Vue 才會建立這個元件並插入 DOM。
可以簡化理解成:
if (isLogin) {
mount(UserPanel)
} else {
unmount(UserPanel)
}所以 v-if 控制的是「有沒有這個節點」。
2. v-show 是顯示切換
v-show 不會移除 DOM,它只是切換元素的 display。
<template>
<UserPanel v-show="isLogin" />
</template>即使 isLogin 是 false,UserPanel 仍然會被建立,只是被加上:
display: none;可以簡化理解成:
el.style.display = isLogin ? '' : 'none'所以 v-show 控制的是「這個節點看不看得到」。
3. 初始成本與切換成本
兩者最重要的取捨是成本不同。
| 指令 | 初始成本 | 切換成本 |
|---|---|---|
v-if | 條件為 false 時較低,因為不建立 DOM | 較高,因為要 mount / unmount |
v-show | 較高,因為一開始就建立 DOM | 較低,因為只切換 display |
簡單判斷:
- 條件很少改變:用
v-if。 - 需要頻繁切換:用
v-show。
4. 生命週期差異
如果 v-if 用在元件上,條件切換會影響元件生命週期。
<UserPanel v-if="visible" />當 visible 從 false 變成 true:
setup / created
-> beforeMount
-> mounted當 visible 從 true 變成 false:
beforeUnmount
-> unmounted但 v-show 不會反覆掛載與卸載元件。它只是改 CSS,因此元件狀態會保留。
這也代表:
v-if重新顯示時,內部狀態可能重新初始化。v-show重新顯示時,內部狀態通常還在。
5. DOM 與 Template Refs 差異
因為 v-if 為 false 時 DOM 不存在,所以你不能保證 ref 一定有值。
<template>
<input v-if="visible" ref="inputRef" />
</template>如果 visible 是 false:
inputRef.value // nullv-show 則不同,DOM 一開始就存在:
<template>
<input v-show="visible" ref="inputRef" />
</template>即使看不見,ref 通常仍可取得 DOM 元素。
二、 追問題庫
Q1:v-if 和 v-show 最大差異是什麼?
v-if 是條件渲染,會建立或銷毀 DOM。v-show 是顯示切換,DOM 一直存在,只透過 display: none 隱藏。
Q2:什麼情況用 v-if?
適合:
- 條件不常變。
- 初始狀態通常不顯示。
- 元件很重,不希望一開始就建立。
- 權限控制,不符合條件時不應該出現在 DOM。
- 切換時希望重新初始化狀態。
例如:
<AdminPanel v-if="user.role === 'admin'" />如果不是管理員,這個區塊就不應該被建立。
Q3:什麼情況用 v-show?
適合:
- 頻繁切換顯示狀態。
- Tab 內容、Dropdown、Tooltip、展開收合。
- 想保留 DOM 狀態或元件內部狀態。
- 切換成本比初始渲染成本更重要。
例如:
<DropdownMenu v-show="opened" />Dropdown 可能會頻繁開關,用 v-show 可以避免每次都 mount / unmount。
Q4:v-show 能用在 <template> 上嗎?
不行。
v-show 的本質是修改元素的 display,所以它需要真實 DOM 元素。<template> 本身不會渲染成 DOM,因此不能用 v-show。
<!-- 不適合 -->
<template v-show="visible">
<p>content</p>
</template>如果你需要控制一組節點是否渲染,可以用 v-if:
<template v-if="visible">
<p>content</p>
</template>或包一層真實元素:
<div v-show="visible">
<p>content</p>
</div>Q5:v-if 和 v-for 可以一起用嗎?
不建議放在同一個元素上。
<!-- 不建議 -->
<li
v-for="item in list"
v-if="item.visible"
:key="item.id"
>
{{ item.name }}
</li>比較好的做法是先用 computed 過濾:
const visibleList = computed(() => {
return list.value.filter(item => item.visible)
})<li
v-for="item in visibleList"
:key="item.id"
>
{{ item.name }}
</li>這樣意圖更清楚,也避免每次渲染時把判斷混在模板裡。
Q6:v-if 和 v-show 對 CSS transition 有差嗎?
有。
v-if 是元素進入與離開 DOM,通常對應 enter / leave transition。
v-show 是 display 切換,也可以搭配 <Transition>,但它不會銷毀元素,適合做顯示隱藏的過渡。
如果是高度、透明度、位置動畫,還要考慮瀏覽器渲染成本。可以延伸讀:瀏覽器渲染管線與 DOM 操作成本。
三、 實作題
題目:Modal 應該用 v-if 還是 v-show?
假設有一個 Modal:
<Modal v-if="opened" />或:
<Modal v-show="opened" />你會怎麼選?
答案不是固定的,要看需求。
情境一:很少打開,內容很重
例如 Modal 裡有大量表單、圖表、API 請求或第三方套件。
<Modal v-if="opened" />理由:
- 初始不建立,減少首屏成本。
- 關閉時卸載,釋放部分資源。
- 下次打開可以重新初始化。
情境二:頻繁開關,需要保留狀態
例如使用者正在填表,關閉後再打開,希望內容還在。
<Modal v-show="opened" />理由:
- DOM 和元件狀態保留。
- 開關切換成本低。
- 不會每次重新跑 mounted 邏輯。
情境三:需要兼顧初始成本與狀態保留
可以用「第一次打開才建立,之後用 v-show 切換」:
<Modal
v-if="hasOpened"
v-show="opened"
/>watch(opened, (value) => {
if (value) {
hasOpened.value = true
}
})這個模式適合比較重、但開過後希望保留狀態的元件。
四、 資深視角
1. 指令選擇背後是資源管理
v-if 和 v-show 的差異,不只是「有沒有 display none」。它其實是在問:
- 要不要建立這個 DOM?
- 元件狀態要不要保留?
- 副作用要不要跟著清理?
- 首屏成本重要,還是切換成本重要?
- 這個元素隱藏時能不能被使用者或輔助技術接觸到?
這些都是資源管理與互動語意問題。
2. 權限控制更適合 v-if
如果一個區塊不應該被某些使用者看到,v-if 通常比 v-show 更合理。
<DeleteButton v-if="canDelete" />v-show 只是視覺隱藏,DOM 仍存在。雖然前端本來就不能作為真正安全邊界,但在 UI 語意上,不該出現的東西就不要渲染。
真正的權限仍然要由後端驗證。
3. 效能問題要看整體場景
如果一個元素很小,v-if 或 v-show 的差異通常不重要。
真正需要在意的是:
- 大型組件。
- 切換頻率高。
- 內部有昂貴初始化。
- 隱藏區塊裡有大量子節點。
- 切換時有動畫或 layout 變化。
所以面試回答不要絕對化。說「頻繁切換用 v-show,不頻繁用 v-if」是基本答案;能補上狀態保留、生命週期、首屏成本與權限語意,才是更完整的答案。
總結
| 面向 | v-if | v-show |
|---|---|---|
| 本質 | 條件渲染 | CSS 顯示切換 |
| DOM | false 時不存在 | 永遠存在 |
| 初始成本 | 條件 false 時較低 | 較高 |
| 切換成本 | 較高 | 較低 |
| 生命週期 | 會 mount / unmount | 不會反覆 mount / unmount |
| 狀態保留 | 通常不保留 | 通常保留 |
支援 <template> | 支援 | 不支援 |
| 適合場景 | 不常切換、權限控制、延後建立 | 頻繁切換、Tab、Dropdown、狀態保留 |
一句完整的面試回答可以是:
v-if是真正的條件渲染,條件為 false 時 DOM 和元件都不會建立,切換時會觸發 mount / unmount,所以初始成本低但切換成本高。v-show會先建立 DOM,只透過display: none控制顯示,切換成本低且能保留元件狀態,但初始成本較高。實務上,不常切換或權限控制用v-if,頻繁切換或需要保留狀態用v-show。