首页 > 编程笔记 > JavaScript笔记 阅读:19

Vue条件渲染指令详解(v-if和v-show指令)

在实际项目开发中,有两种场景非常常见:
无论哪一种场景,都只有在满足某种条件后才能渲染显示。在 Vue 中将其称为条件渲染,可以通过 v-if 相关指令或 v-show 指令实现。

Vue v-if指令

v-if 指令用于控制元素的显示或者隐藏,其相关指令包含 v-if、v-else 和 v-else-if。

v-if 与 v-else-if 指令的表达式类型需要是布尔类型,当结果为 true 时,也就是满足条件后,才显示对应的元素;v-else 指令不需要指定表达式,只需要指定属性名,当元素前面的 v-if 和 v-else-if 指令都不满足条件时才会显示。

如果只有一个页面的条件渲染,则推荐使用 v-if 指令来渲染;如果有两个页面的条件渲染,则推荐配合使用 v-if 与 v-else 指令来渲染;如果超过两个页面的条件渲染,则推荐配合使用 v-if、v-else-if 和 v-else 指令来渲染。

先阅读下方代码并思考其运行效果,然后在下方代码的基础上进行优化:
<div id="app">
  <h1>你的入学测试得分:{{score}}</h1>
  <button @click="examAgain">学习后再复试一次</button>
</div>

<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.31/vue.global.min.js"></script>
<script>
const { createApp } = Vue

createApp({
  data () {
    return {
      score: 55
    }
  },
  methods: {
    examAgain () {
      this.score += 10
    }
  }
}).mount('#app')
</script>
这段代码比较简单,页面上会显示 data 方法中 score 的值和一个按钮,当点击按钮后,score 的值增加 10。初始页面效果如下图所示:


图 1 初始页面效果

点击按钮后的页面效果如下图所示:


图 2 点击按钮后的页面效果

现在的需求是,只有当入学测试得分小于 60 分的时候元素才会显示。此时我们就可以通过 v-if 指令来实现。在 button 按钮上做简单改动,具体如下:
<button @click="examAgain" v-if="score<60">学习后再复试一次</button>
当 v-if 指定的表达式的值为 true 时,元素才会显示。对于上方代码来说,初始时 score 的值为 55,按钮被显示,点击按钮后,因为 score 的值大于 60,所以按钮自动消失了。

现在添加一个新需求,当入学测试得分大于或等于 60 分时,显示绿色的 h3 文本提示;当入学测试得分小于 60 分时,显示红色的 h4 文本提示。

读者可能想到了使用 v-if 指令对 h3 和 h4 标签进行控制,但实际上,Vue 提供了更便捷的方式,前面提到过 v-if 的相关指令,对于这个需求就可以配合使用 v-if 和 v-else 实现。不过需要注意的是,v-else 指令不需要指定表达式。此时 Vue 代码变为下方代码:
<h2 v-if="score>=60" style="color: green;">欢迎来C语言中文网学习!</h2>
<h4 v-else style="color: red;">很遗憾,你的测试没有通过</h4>
v-if 指令的页面效果与上一段代码的页面效果相同,这里不做过多讲解,但当不满足 v-if 指令的条件时,就会显示 v-else 指令所在的元素。此时 data 方法中的 score 值为55,不满足条件,只会显示“很遗憾,你的测试没有通过”。

用户的需求总是多变的。现在需求再次更改:当入学测试得分大于或等于 60 分时,显示绿色的 h2 文本提示;当入学测试得分小于 50 分时,显示红色的 h3 文本提示;当入学测试得分在 50~60分(包括 50 分)时,显示黄色的 h4 文本提示。

此时可以配合使用 v-if、v-else-if 和 v-else 指令来实现。需要注意的是,只有当 v-else-if 指令指定的表达式的值为 true 时,对应的标签才会显示。Vue 代码变为下方代码:
<h2 v-if="score>=60" style="color: green;">欢迎来C语言中文网学习!</h2>
<h3 v-else-if="score>50" style="color: red;">很遗憾,你的测试没有通过</h3>
<h4 v-else style="color: yellow;">此次测试没有完全通过,可选择复试。</h4>

前面都是对一个标签进行条件渲染,那么如果有多个标签要怎么处理呢?

我们可以用 template 标签来包含要实现条件渲染的多个标签,并在 template 标签上使用 v-if 指令来判断元素是否显示。需要注意的是,template 标签只在模板中存在,并不会产生任何 HTML 标签,具体如下:
<h1>你的入学测试得分:{{score}}</h1>
<button @click="examAgain">学习后再复试一次</button>

<template v-if="score>=60">
  <h2>欢迎来C语言中文网学习!</h2>
  <button>去找网站管理员开通VIP会员</button>
  <button>去找答疑老师深入交流技术疑问</button>
  <button>去找就业老师了解就业信息</button>
</template>
运行代码后,因为 score 的值初始为 55,不满足 v-if 指令的条件,所以只显示入学测试得分和“学习后再复试一次”按钮。当点击“学习后再复试一次”按钮后,score 的值更改为 65,满足 v-if 指令的条件,显示其余 3 个按钮。

此时我们观察页面结构,发现没有 template 标签,验证了“template 标签只在模板中存在,并不会产生任何 HTML 标签”的说法。

Vue v-show指令

在 Vue 中,v-show 指令也可以实现条件渲染。当 v-show 指令指定的表达式的值为 true 时,对应的标签才会显示。

下面我们将 v-if 指令中涉及的案例使用 v-show 指令来实现。代码片段 1 如下:
<button @click="examAgain" v-show="score<60">学习后再复试一次</button>
当 score 的值小于 60 时,显示“学习后再复试一次”按钮。

代码片段 2 如下:
<h2 v-show="score>=60" style="color: green;">欢迎来C语言中文网学习!</h2>
<h3 v-show="score<60" style="color: red;">很遗憾,你的测试没有通过……</h3>
当 score 的值大于或等于 60 时,显示“欢迎来C语言中文网学习!”;当 score 的值小于 60 时,显示“很遗憾,你的测试没有通过……”。

代码片段 3 如下:
<h2 v-show="score>=60" style="color: green;">欢迎来C语言中文网学习!</h2>
<h3 v-show="score>50" style="color: red;">很遗憾,你的测试没有通过。</h3>
<h4 v-show="score<50" style="color: yellow;">此次测试没有完全通过,可选择复试。</h4>
当 score 的值大于或等于 60 时,显示“欢迎来C语言中文网学习!”;当 score 的值在 50~60(包括 50)时,会显示“此次测试没有完全通过,可选择复试。”;其余情况则显示“很遗憾,你的测试没有通过。”

因为初始 score 的值是 55,所以当点击按钮时,文本提示会切换显示,按钮也会被隐藏。需要注意的是,v-show 指令是不能与 v-else 和 v-else-if 指令配合使用的。当需要在多个标签之间切换显示时,要使用多个 v-show 指令来实现。还有一点要特别注意,v-show 指令不能用在 template 标签上。

比较v-if和v-show指令

通过前面的学习我们得知,v-if 和 v-show 指令实现的功能是一致的,但实际上,二者内部的实现机制截然不同,这一点是在理论面试时经常被提问的问题。

在初始化解析显示时,如果表达式的值为 true,那么二者的内部处理相同;如果表达式的值为 false,则内部处理完全不同:
在更新数据后,表达式的值变为 true,需要显示标签结构。v-if 指令的标签会新建 HTML 标签结构并显示,而 v-show 指令只需要去除 display 为 none 的样式让标签结构重新显示出来。

当再次更新数据后,表达式的值变为 false,需要隐藏标签结构。v-if 指令的标签直接被删除,内存中 v-show 指令不再有对应的 DOM 结构;v-show 指令的标签通过指定 display 为 none 的样式来隐藏标签结构。

通过下方代码进行验证,Vue 代码如下:
<div id="app">
  <h1 v-if="isShow">C语言中文网 1</h1>
  <h2 v-show="isShow">C语言中文网 2</h2>
  <button @click="isShow=!isShow">切换标识</button>
</div>

JavaScript代码如下:
const { createApp } = Vue

createApp({
  data () {
    return {
      isShow: false
    }
  }
}).mount('#app')
在上方代码中,通过 v-if 指令控制 h1 标题的显示/隐藏,通过 v-show 指令控制 h2 标题的显示/隐藏。

在初始显示时,由于 isShow 的值为 false,因此 h1 与 h2 两个标题都不可见。通过查看页面结构可以发现 h1 标题不存在,但 h2 标题是存在的,只是通过指定 display 为 none 的样式来隐藏标签结构。

点击“切换标识”按钮对 isShow 标识进行取反,isShow 的值更新为 true。此时 h1 和 h2 两个标题都会显示,但通过 v-if 指定控制的 h1 标题是新创建的,而 h2 标题是通过删除 display 为 none 的样式显示出来的。

当再次点击“切换标识”按钮时,isShow 的值更新为 false。此时 h1 标题和 h2 标题都会消失,但 v-if 指令控制的 h1 标题被删除,而通过 v-show 指令控制的 h2 标题存在,只是添加了 display 为 none 的样式。

最后简单总结一下 v-if 与 v-show 指令的区别,在隐藏时,v-if 指令会删除标签,而 v-show 指令只是通过样式控制标签不显示;当再次显示时,v-if 指令需要重新创建标签,而 v-show 指令只需要更新一下样式就可以显示。

对于使用场景的选择,如果条件渲染的条件变化相对频繁或要控制的标签结构比较大,那么选择 v-show 指令比较合适。因为 v-if 指令在从隐藏变为显示时,需要重新创建 DOM 结构,效率相对低一些,但 v-show 指令在隐藏时,标签结构没有被删除,比 v-if 指令占用的内存更大一些。这也就是编程世界中经常说到的:“以空间换时间的技术”,即用更大的占用空间,换取后面更少的执行时间。

还有一点需要注意的是,如果初始渲染条件的值为 false,则 v-if 指令是不会解析模板产生 HTML 标签的,有时也称它为懒加载,但 v-show 指令不是懒加载。

相关文章