DAY06 | 跟 Vue.js 認識的30天 - Vue 的條件渲染(`v-if`、`v-show`)

在 JS 中我們是利用 if(condition){statement1}else{statement2} 來設定條件並決定執行哪一段陳述式(statement),如果 conditiontruthy 就執行 statement1 ,否則就執行 statement2

但在 Vue 裡可以利用 v-ifv-else-ifv-else 指令快速設定條件,並決定執行哪段 HTML 元素。

v-if 指令

語法解釋

僅有 v-if

1
2
3
4
5
6
7
8
9
10
11
12
<!--v-if="條件式(condition)"-->
<!--成立即顯示-->
<h1 v-if="awesome">Vue is awesome!</h1>
<script>
const vm = new Vue({
el:'#vm',
data:{
// 可以利用 truthy 或 falsy 來決定條件是否成立
awesome: 0,
}
})
</script>

成立時,畫面上即會顯示該元素,如果不成立,打開 Chrome 開發工具會發現一個佔位標籤 <!---->

v-ifv-else-ifv-else

1
2
3
<h3 v-if="Num>9">First</h3>
<h3 v-else-if="Num>5">Second</h3>
<h3 v-else>Third</h3>

v-ifv-else-ifv-else 這幾個指令要緊緊相依,中間不能插入其他的不相干的元素,另外在有 v-else 的情況下,就不會出現佔位標籤 <!----> ,這是因為在 v-ifv-else-ifv-else 是一種切換的關係,一定會有其中一個顯示在畫面上,所以不像是單純只有 v-if 時,當 v-if 不成立時,HTML 就沒有留位置給它,所以需要靠佔位標籤 <!----> 來留位置。

利用 template 標籤來將條件分組

利用 template 標籤分組的好處是甚麼?
簡單來說就是畫面上不會出現太多的 <div> 來為要呈現的區塊分組,又或是在 HTML 使用太多的 v-ifv-else
可以比較一下這幾種用法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!--第一種寫法,運用很多div-->
<div v-if="templateReveal">
<h1>利用div</h1>
<p>Paragraph 1</p>
<p>Paragraph 1</p>
</div>
<div v-else>
<h1>利用div</h1>
<p>Paragraph 2</p>
<p>Paragraph 2</p>
</div>
<!--第二種寫法,都加上v-if-->
<h1 v-if="templateReveal">全都加上v-if</h1>
<h1 v-else>全都加上v-else</h1>
<p v-if="templateReveal">Paragraph 1</p>
<p v-else>全都加上v-else</p>
<p v-if="templateReveal">Paragraph 1</p>
<p v-else>全都加上v-else</p>
<!--第三種寫法,使用template-->
<template v-if="templateReveal">
<h1>使用template</h1>
<p>Paragraph 1</p>
<p>Paragraph 1</p>
</template>
<template v-else>
<h1>使用template</h1>
<p>Paragraph 2</p>
<p>Paragraph 2</p>
</template>

第二種實在是非常麻煩,完全不用考慮,但第一種跟第三種的差別在哪裡?

使用 <template> 可以製作一個群組,但是在 HTML 上不會顯示出 <template> 標籤,使用 <div> 同樣可以做出一個群組,但是在 HTML 上會顯示出 <div> 標籤,單純只看包裹群組的的標籤是否還有額外的作用,有的話就須使用 <div> 標籤,例如為群組加上 class 樣式,如果使用 <template> 標籤的話,因為會消失,所以會導致群組無法吃到 class 樣式。

v-if 指令搭配 key Atttribute

Vue 為了能快速的渲染畫面,所以在資料更改後,對於那些沒更改的資料會繼續使用,而非重新渲染,所以當我們製作群組、更動資料時,如果群組的元素幾乎是一樣的狀況下, Vue 會重複使用,而非重新渲染,這個問題在之後的 v-for 也會有。

可以參考 Vue 文件提供的例子:元素切換

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address">
</template>

在切換的過程中,輸入在 <input> 中的文字,並不會隨著 loginType 的不同而有所改變(即使切換還是存在剛剛輸入的文字)。如同上面所說的 Vue 為了快速渲染畫面,針對幾乎相同的元素模板將重複使用。

使用 key Atttribute 解決模板重複使用的問題

為了解決上面的問題, Vue 提供了 key Atttribute 來表達這2個元素是不同的,不要去複用。

資料切換而模板重複使用造成問題的通常是表單元素 <input> ,所以可以在 <input> 上加入 key Atttribute 來解決複用的問題。

1
2
3
4
5
6
7
8
<template v-if="loginType === 'username'">
<label>Username</label>
<input placeholder="Enter your username" key="username-input">
</template>
<template v-else>
<label>Email</label>
<input placeholder="Enter your email address" key="email-input">
</template>

v-show 指令

v-show 同樣是針對元素出現與否的指令,跟 v-if 最大的不同是在 v-show是利用 CSS 切換 display:nonedisplay:block 來決定元素是否顯示在畫面,在 DOM tree 是可以找到該元素的,而 v-if 是整盤端走,在 DOM tree 是無法找到的。

1
<h1 v-show="show">我是v-show</h1>

v-ifv-show 的使用時機

當**有頻繁切換需要時,使用 v-show ,如果沒有的話,就使用 v-if**,這是因為 v-show 不論初始值是真值(Truthy)還是假值(Falsy)都一定會先渲染出來,但是 v-if 初始值如果是假值,則不會去渲染畫面,但在切換的過程則需要不斷的重建或銷毀,也因此 v-show 會有較高的初始渲染效能,而 v-if 則是在切換的過程,使用較多的效能。

Demo:

See the Pen [DAY06]跟 Vue.js 認識的30天 - Vue 的條件渲染 by Celeste6666 (@celeste6666) on CodePen.

參考資料:
Vue.js-条件渲染
Yes