前言

学习目标
- v-if 和 v-show 之间的区别?面试题
v-if 控制是否生成 DOM
v-show 控制 DOM 的 display 样式
详情见笔记:「v-if 对比 v-show」链接
- 如何实现分组条件渲染?
<template>+ v-if结合使用。
使用<template>将需要渲染的元素包裹成组,使用 v-if 控制 <template>即可。
- 如何使用 key 管理可复用元素的渲染?
若切换后,发现有些元素没必要重新渲染,只要在原始的元素(即将被销毁的元素)稍作改动即可。那么 vue 将不会重新渲染它,vue 会直接改动原有的元素。
若想要让某个元素重新渲染,可以给它绑定指定的 key 值。
- 什么时候使用 v-if,什么时候使用 v-show?
元素需要频繁切换显示和隐藏,使用 v-show;否则使用 v-if。
主要内容

参考资料
条件渲染
v-if
v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回 truthy 值的时候被渲染。
<h1 v-if="awesome">Vue is awesome!</h1>
也可以用 v-else 添加一个“else 块”:
<h1 v-if="awesome">Vue is awesome!</h1><h1 v-else>Oh no 😢</h1>
若 awesome 不是 truthy,那么显示 v-else 的内容,否则显示 i-if 的内容。
在 元素上使用 v-if 条件渲染分组因为 v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
若多个元素在结构上不是挨着的,比如:想要同时控制 Title 和 Paragraph 2 的显示/隐藏。可以使用下面这种写法。
<h1 v-if="ok">Title</h1>
<p>Paragraph 1</p>
<p v-if="ok">Paragraph 2</p>
demo1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
<p>Paragraph 3</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
ok: false
}
});
</script>
</body>
</html>

如果元素在 html 结构上是挨在一起的,那么用 template 包裹这些元素,然后控制 template 即可。
demo2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<h1 v-if="ok">Title</h1>
<p v-if="ok">Paragraph 1</p>
<p v-if="ok">Paragraph 2</p>
<p>Paragraph 3</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
ok: false
}
});
</script>
</body>
</html>
也可以实现同样的效果,如果元素在 html 结构上,不是挨在一起的,那么可以使用这种实现方式,它更加灵活。
v-else
你可以使用 v-else 指令来表示 v-if 的“else 块”:
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-else-if
v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:
demo3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
type: 'B'
}
});
</script>
</body>
</html>
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。


页面中渲染啥,最终取决于 type 的值,我们可以在控制台通过给 vm.type 重新赋值的形式来观察页面的变化,体验条件渲染。
用 key 管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
demo4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<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>
<p>
<button @click="loginType = loginType === 'username' ? 'email' : 'username'">Toggle login type</button>
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
loginType: 'username'
},
});
</script>
</body>
</html>
那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素, 不会被替换掉——仅仅是替换了它的 placeholder。
自己动手试一试,在输入框中输入一些文本,然后按下切换按钮:

vue 很智能地发现,input 并没有必要重新渲染,只要替换 placeholder 即可,这样操作效率更高。

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可:
<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>
现在,每次切换时,输入框都将被重新渲染。请看:

通过绑定 key 的方式,明确告诉 vue,这俩 input 不是一个东西,如果切换显示的话,它们得重新渲染。

注意,<label> 元素仍然会被高效地复用,因为它们没有添加 key attribute。
小技巧
Q:如何直观地查看哪些元素重新渲染了?
A:打开浏览器控制台,然后快速地点击按钮,查看 「Elements」对应元素的变化。(以 chrome 为例)

会发现,在变化时,input 元素并没有变色,说明它没有重新渲染。
v-show
另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。
⚠️
v-show 不支持 元素,也不支持 v-else。
v-if 对比 v-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做 —— 直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
面试题常考,v-if 和 v-show 之间的差别。
v-if 和 v-for 一起使用
不推荐同时使用 v-if 和 v-for。请查阅风格指南(链接)以获取更多信息。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。请查阅列表渲染(下一节笔记)指南以获取详细信息。
v-if 是一个指令,所以必须将它添加到一个元素上。但是如果想切换多个元素呢?此时可以把一个 元素当做不可见的包裹元素,并在上面使用 v-if。最终的渲染结果将不包含 元素。
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
若多个元素在结构上不是挨着的,比如:想要同时控制 Title 和 Paragraph 2 的显示/隐藏。可以使用下面这种写法。
<h1 v-if="ok">Title</h1>
<p>Paragraph 1</p>
<p v-if="ok">Paragraph 2</p>
demo1
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<template v-if="ok">
<h1>Title</h1>
<p>Paragraph 1</p>
<p>Paragraph 2</p>
</template>
<p>Paragraph 3</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
ok: false
}
});
</script>
</body>
</html>

如果元素在 html 结构上是挨在一起的,那么用 template 包裹这些元素,然后控制 template 即可。
demo2
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<h1 v-if="ok">Title</h1>
<p v-if="ok">Paragraph 1</p>
<p v-if="ok">Paragraph 2</p>
<p>Paragraph 3</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
ok: false
}
});
</script>
</body>
</html>
也可以实现同样的效果,如果元素在 html 结构上,不是挨在一起的,那么可以使用这种实现方式,它更加灵活。
v-else
你可以使用 v-else 指令来表示 v-if 的“else 块”:
<div v-if="Math.random() > 0.5">
Now you see me
</div>
<div v-else>
Now you don't
</div>
v-else 元素必须紧跟在带 v-if 或者 v-else-if 的元素的后面,否则它将不会被识别。
v-else-if
v-else-if,顾名思义,充当 v-if 的“else-if 块”,可以连续使用:
demo3
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<div v-if="type === 'A'">
A
</div>
<div v-else-if="type === 'B'">
B
</div>
<div v-else-if="type === 'C'">
C
</div>
<div v-else>
Not A/B/C
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
type: 'B'
}
});
</script>
</body>
</html>
类似于 v-else,v-else-if 也必须紧跟在带 v-if 或者 v-else-if 的元素之后。


页面中渲染啥,最终取决于 type 的值,我们可以在控制台通过给 vm.type 重新赋值的形式来观察页面的变化,体验条件渲染。
用 key 管理可复用的元素
Vue 会尽可能高效地渲染元素,通常会复用已有元素而不是从头开始渲染。这么做除了使 Vue 变得非常快之外,还有其它一些好处。例如,如果你允许用户在不同的登录方式之间切换:
demo4
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>模板语法 - 条件渲染</title>
</head>
<body>
<div id="app">
<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>
<p>
<button @click="loginType = loginType === 'username' ? 'email' : 'username'">Toggle login type</button>
</p>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue@2"></script>
<script>
const vm = new Vue({
el: "#app",
data: {
loginType: 'username'
},
});
</script>
</body>
</html>
那么在上面的代码中切换 loginType 将不会清除用户已经输入的内容。因为两个模板使用了相同的元素, 不会被替换掉——仅仅是替换了它的 placeholder。
自己动手试一试,在输入框中输入一些文本,然后按下切换按钮:

vue 很智能地发现,input 并没有必要重新渲染,只要替换 placeholder 即可,这样操作效率更高。

这样也不总是符合实际需求,所以 Vue 为你提供了一种方式来表达“这两个元素是完全独立的,不要复用它们”。只需添加一个具有唯一值的 key attribute 即可:
<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>
现在,每次切换时,输入框都将被重新渲染。请看:

通过绑定 key 的方式,明确告诉 vue,这俩 input 不是一个东西,如果切换显示的话,它们得重新渲染。

注意,<label> 元素仍然会被高效地复用,因为它们没有添加 key attribute。
小技巧
Q:如何直观地查看哪些元素重新渲染了?
A:打开浏览器控制台,然后快速地点击按钮,查看 「Elements」对应元素的变化。(以 chrome 为例)

会发现,在变化时,input 元素并没有变色,说明它没有重新渲染。
v-show
另一个用于根据条件展示元素的选项是 v-show 指令。用法大致一样:
<h1 v-show="ok">Hello!</h1>
不同的是带有 v-show 的元素始终会被渲染并保留在 DOM 中。v-show 只是简单地切换元素的 CSS property display。
⚠️ v-show 不支持 元素,也不支持 v-else。
v-if 对比 v-show
v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做 —— 直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。
一般来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要非常频繁地切换,则使用 v-show 较好;如果在运行时条件很少改变,则使用 v-if 较好。
面试题常考,v-if 和 v-show 之间的差别。
v-if 和 v-for 一起使用
不推荐同时使用 v-if 和 v-for。请查阅风格指南(链接)以获取更多信息。
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级。请查阅列表渲染(下一节笔记)指南以获取详细信息。
