v-show
和 v-if
是 Vue.js 中兩個非常重要的指令,都用于條件性地顯示或隱藏元素,但它們的實現方式和適用場景有本質區別。
簡單來說,最核心的區別是:
v-if
是 “真正的”條件渲染,它會確保在切換過程中條件塊內的事件監聽器和子組件適當地被銷毀和重建。v-show
只是簡單地切換 CSS 屬性display: none
。
下面從多個維度進行詳細的對比。
對比表格
特性 | v-if | v-show |
---|---|---|
實現機制 | 動態添加/移除 DOM 元素 | 切換 CSS 的 display: none 屬性 |
初始渲染成本 | 高(如果初始為 false,則什么都不做,直到第一次為 true 時才渲染) | 高(無論初始條件如何,元素都會被編譯并渲染,只是通過 CSS 隱藏) |
切換開銷 | 高(銷毀和重建組件/元素、觸發生命周期鉤子) | 低(只是切換 CSS 屬性,非常高效) |
生命周期 | 會觸發 組件的 created , mounted , destroyed 等生命周期鉤子 | 不會觸發 任何生命周期鉤子(因為組件始終存在,只是被隱藏) |
編譯/惰性 | 惰性的:如果初始條件為假,則不會編譯或渲染,直到條件第一次變為真。 | 非惰性的:無論初始條件如何,元素都會被編譯并保留在 DOM 中。 |
用法 | 任何條件渲染 | 適用于需要非常頻繁切換的場景 |
不適合場景 | 需要非常頻繁切換的場景(因為切換開銷大) | 不適合初始條件為假且永遠不需要顯示的情況(因為仍然會渲染) |
與 v-else 配合 | 支持 | 不支持 |
與 <template> 配合 | 支持(可以包裹多個元素) | 不支持 |
詳細說明與示例
1. 實現機制與 DOM 結構
v-if
:
當條件為 false
時,對應的元素或組件完全不會出現在 DOM 中。當條件變為 true
時,Vue 會開始編譯并渲染它們,并將其插入到 DOM 中。
<div v-if="isVisible">使用 v-if 控制</div>
- 當
isVisible
為false
時,檢查元素結構,你會發現這個<div>
根本不存在。 - 當
isVisible
為true
時,這個<div>
會被創建并插入到 DOM 中。
v-show
:
無論條件為何,元素始終會被編譯并保留在 DOM 中。它只是通過內聯的 CSS 樣式 display: none
來切換顯示和隱藏。
<div v-show="isVisible">使用 v-show 控制</div>
- 當
isVisible
為false
時,檢查元素結構,你會發現這個<div>
仍然在 DOM 中,但它有內聯樣式style="display: none;"
。 - 當
isVisible
為true
時,內聯樣式會被移除,變為style=""
,元素正常顯示。
2. 生命周期
由于 v-if
會真正地銷毀和重建元素及其子組件,因此它會觸發完整的生命周期鉤子。
<ChildComponent v-if="isVisible" />
- 當
isVisible
從true
變為false
時,ChildComponent
會被銷毀,觸發beforeDestroy
和destroyed
鉤子。 - 當
isVisible
從false
變為true
時,ChildComponent
會重新創建,觸發beforeCreate
,created
,beforeMount
,mounted
等鉤子。
而對于 v-show
,由于組件始終存在于 DOM 中,只是被隱藏,所以無論怎么切換,它的生命周期鉤子都只會在初始渲染時觸發一次。
3. 性能考量
選擇使用哪個指令,主要取決于你需要的切換頻率。
-
需要頻繁切換時(如:切換標簽頁、顯示/隱藏過濾器、toggle 開關),使用
v-show
。- 原因:它的切換成本極低,僅僅是修改 CSS,避免了頻繁銷毀和重建組件帶來的性能開銷。
-
運行時條件很少改變,或者初始條件很可能為 false 時,使用
v-if
。- 原因:它具有惰性,如果初始不為真,可以避免不必要的編譯和渲染成本,從而加快初始頁面加載速度。
總結與如何選擇
記住這個簡單的原則:
v-if
就像是 “徹底銷毀”。不用的時候直接拆掉,用的時候再重新蓋。適合變化不頻繁、條件判斷復雜(常與v-else-if
連用)或者對初始加載性能有要求的場景。v-show
就像是 “拉上窗簾”。東西還在屋里,只是你看不見。適合需要非常頻繁切換顯示狀態的場景。
簡單決策流程圖:
- 需要頻繁顯示/隱藏嗎? (是 -> 用
v-show
) - 這個元素在大多數情況下根本不需要顯示嗎? (是 -> 用
v-if
,節省初始渲染開銷) - 條件邏輯復雜,需要配合
v-else
或v-else-if
嗎? (是 -> 用v-if
) - 不確定?默認先考慮使用
v-if
,因為它的惰性特性在很多時候對性能更友好,除非你遇到了明顯的性能問題(比如切換卡頓)再考慮換成v-show
。