v-if还是v-show,这是个问题

533 阅读2分钟

什么时候该用v-if,什么时候该用v-show?
相信看过Vue文档的小伙伴们都能很快下定这么一个结论。

  1. 如果需要非常频繁地切换,则使用 v-show 较好
  2. 如果在运行时条件很少改变,则使用 v-if 较好 但是,这样子真的就对吗? 先来写一个例子看看
<div id="app">
  <div v-show="false">use v-show</div>
  <div v-if="false">use v-if</div>
</div>

通过查看控制台我们可以得出和官网相同的结论
1653705205(1).png

v-if 是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建。
v-if 也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
相比之下,v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 进行切换。

我们再来换第二个例子看看

<template>
  <div id="app">
    <div
      class="menu"
      :key="id"
      @click="handleClick(id)"
      v-for="{ id, children } in list"
    >
      <header class="menu__header">{{ id }}</header>
      <div class="menu__list" v-if="curId === id">
        <div class="menu__list__item" :key="child" v-for="child in children">
          {{ child }}
        </div>
      </div>
    </div>
  </div>
</template>
<script>
export default {
  name: "App",
  data() {
    return {
      curId: void 0,
      list: Array(100)
        .fill(0)
        .map((_, id) => {
          const children = Array(2000)
            .fill(0)
            .map((_, cid) => `${id}-${cid}`);
          return { id, children };
        }),
    };
  },
  methods: {
    handleClick(id) {
      this.curId = this.curId === id ? void 0 : id;
    },
  },
};
</script>
<style lang="less">
#app {
  color: white;
  text-align: center;
  .menu {
    margin-top: 1px;
    &__header {
      height: 20px;
      line-height: 20px;
      background-color: blue;
      cursor: pointer;
    }
    &__list__item {
      height: 20px;
      line-height: 20px;
      background-color: lightskyblue;
      margin-top: 1px;
    }
  }
}
</style>

在上面中我们设置了100个父节点,同时每个父节点中有2000个子节点。
当我们使用v-show控制会发现切换节点显隐时卡顿现象非常的明显,而使用v-if使反倒会更加的流畅,从而得出一个与上面完全相反的结论,这是为什么呢?
通过谷歌的Performance对其切换进行监听可以发现,在使用v-show时耗时较长并且其中大多时间都在于执行script脚本

1.png

2.png 这是因为使用v-show时,Vue进行diff更新需要花费更多的时间导致的。同时因为v-show仅仅对节点使用了display: none属性,实际节点还是存在的,也就意味着它将会占据更多的内存。

4.png

3.png 其它应用场景
在实际开发过程中,有时候我们会用到如elementUI之类的UI库,根据官方文档,我们很容易就会写出下面这样的例子

<el-dialog
  title="提示"
  :visible.sync="dialogVisible"
  width="30%"
  :before-close="handleClose"
  ><span>这是一段信息</span>
  <span slot="footer" class="dialog-footer">
    <el-button @click="dialogVisible = false">取 消</el-button>
    <el-button type="primary" @click="dialogVisible = false">确 定</el-button>
  </span>
</el-dialog>

然而却很少人会注意到其实el-dialog的visible也是通过display: none来进行控制的。也就是说当你的页面存在大量弹窗的时候,尽管你没有对弹窗的内容进行任何操作,但是你的页面还是会发生明显的卡顿。这时候不妨尝试使用v-if来对弹窗进行控制,如果担心弹窗动画问题,则还可以通过二次封装将visible以及nextTick配合来实现理想效果。
总结
v-if还是v-show,这不是个问题。

  1. 若当前页面节点较少且切换频繁时我们可以使用v-show
  2. 若当前页面节点较多,则也可以尝试使用v-if来减少节点