Skip to content

条件渲染

v-if

v-if 指令用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值时才被渲染。

<h1 v-if="awesome">Vue is awesome!</h1>

v-else

你也可以使用 v-elsev-if 添加一个“else 区块”。

vue
<button @click="awesome = !awesome">Toggle</button>

<h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>

一个 v-else 元素必须跟在一个 v-if 或者 v-else-if 元素后面,否则它将不会被识别。

v-else-if

顾名思义,v-else-if 提供的是相应于 v-ifelse if 区块。它可以连续多次重复使用:

vue
<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>

v-else 类似,一个使用 v-else-if 的元素必须紧跟在一个 v-if 或一个 v-else-if 元素后面。

<template> 上的 v-if

因为 v-if 是一个指令,他必须依附于某个元素。但如果我们想要切换不止一个元素呢?在这种情况下我们可以在一个 <vue> 元素上使用 v-if,这只是一个不可见的包装器元素,最后渲染的结果并不会包含这个 <vue> 元素。

vue
<template v-if="ok">
  <h1>Title</h1>
  <p>Paragraph 1</p>
  <p>Paragraph 2</p>
</template>

v-elsev-else-if 也可以在 <template> 上使用。

v-show

另一个可以用来按条件显示一个元素的指令是 v-show。其用法基本一样:

vue
<h1 v-show="ok">Hello!</h1>

不同之处在于 v-show 会在 DOM 渲染中保留该元素;v-show 仅切换了该元素上名为 display 的 CSS 属性。

v-show 不支持在 <vue> 元素上使用,也不能和 v-else 搭配使用。

v-if vs. v-show

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建。

v-if 也是惰性的:如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。

相比之下,v-show 简单许多,元素无论初始条件如何,始终会被渲染,只有 CSS display 属性会被切换。

总的来说,v-if 有更高的切换开销,而 v-show 有更高的初始渲染开销。因此,如果需要频繁切换,则使用 v-show 较好;如果在运行时绑定条件很少改变,则 v-if 会更合适。

案例

v-show 和 v-if 条件渲染

目标:控制标签的隐藏或出现

  • 语法:
    • v-show="vue 变量"
    • v-if="vue 变量"
  • 原理
    • v-show 用的 display:none 隐藏 (频繁切换使用)
    • v-if 直接从 DOM 树上移除
  • 高级
    • v-else 使用
html
<script setup>
  import { ref } from "vue";

  const is_ok = ref(true);
  const age = ref(15);
</script>

<vue>
  <div>
    <!-- v-show 或者 v-if
       v-show="vue 变量"
       v-if="vue 变量"
     -->
    <h1 v-show="is_ok">v-show 的盒子</h1>
    <h1 v-if="is_ok">v-if 的盒子</h1>
    <!--
      v-show 隐藏:采用 display:none   // 频繁切换
      v-if 隐藏:采用从 DOM 树直接移除 // 移除
     -->

    <div>
      <!-- v-if 和 v-else 使用 -->
      <p v-if="age > 18">我成年了</p>
      <p v-else>还得多吃饭</p>
    </div>
  </div>
</vue>

<style scoped></style>

总结:使用 v-show 和 v-if 以及 v-else 指令,方便通过变量控制一套标签出现/隐藏

案例 - 折叠面板

目标:点击展开或收起时,把内容区域显示或者隐藏

参考 bootstrap5 折叠面板 ,只需要完成一个元素的展开与收起即可。

此案例使用了 less 语法,项目中下载模块

bash
# .less
npm install -D less

只有标签和样式

vue
<script setup>
import { ref } from "vue";

const is_show = ref(true);
const btn = () => {
  // 3. 点击时,把值改成 false
  is_show.value = !is_show.value;
};
</script>

<vue>
  <div>
    <h3>案例:折叠面板</h3>
    <div>
      <div class="title">
        <h4>芙蓉楼送辛渐</h4>
        <!-- 1.绑定点击事件 -->
        <span class="btn" @click="btn">
          <!-- 4. 根据 isShow 的值显示不同文字 -->
          {{ is_show ? '收起' : '展开' }}
        </span>
      </div>
      <!-- 2. v-show 配合变量来控制标签隐藏出现 -->
      <div class="container" v-show="is_show">
        <p>寒雨连江夜入吴,</p>
        <p>平明送客楚山孤。</p>
        <p>洛阳亲友如相问,</p>
        <p>一片冰心在玉壶。</p>
      </div>
    </div>
  </div>
</vue>

<style scoped lang="less">
body {
  background-color: #ccc;

  #app {
    width: 400px;
    margin: 20px auto;
    background-color: #fff;
    border: 4px solid blueviolet;
    border-radius: 1em;
    box-shadow: 3px 3px 3px rgba(0, 0, 0, 0.5);
    padding: 1em 2em 2em;

    h3 {
      text-align: center;
    }

    .title {
      display: flex;
      justify-content: space-between;
      align-items: center;
      border: 1px solid #ccc;
      padding: 0 1em;
    }

    .title h4 {
      line-height: 2;
      margin: 0;
    }

    .container {
      border: 1px solid #ccc;
      padding: 0 1em;
    }

    .btn {
      /* 鼠标改成手的形状 */
      cursor: pointer;
    }
  }
}
</style>