vue条件渲染使用场景(v-if VS v-show)

2,962 阅读3分钟

v-if和v-show都是条件渲染。

第一个区别是v-if可以结合v-else,写出类似于js的渲染逻辑。比如:如果 n=true,渲染1, 如果 n = false,渲染2;
如果用v-if实现:

<template>
    <div>
        <div v-if="n">1</div>
        <div v-else>2</div>
    </div>
</template>

如果用v-show实现:

<template>
    <div>
        <div v-show = "n">1</div>
        <div v-show = "!n">2</div>
    </div>
</template>

第二个区别是,从实现原理上来说:
v-if 是通过控制 dom 的生成和移除,也就是“真正“的条件渲染,因为它会确保在切换过程中条件内的事件监听起和子组件适当地被销毁和重建。而且 v-if 也是惰性的,如果在初始化时条件为假,则什么都不做,直到条件第一次为真时,才会开始渲染条件块。
v-show 比较简单了,实际上无论条件是什么,元素总是会被渲染,只是通过简单的基于css进行切换。

  1. 手段:v-if是动态的向DOM树内添加或者删除DOM元素;v-show是通过设置DOM元素的display样式属性控制显隐。
  2. 编译过程:v-if切换有一个局部编译/卸载的过程,切换过程中合适地销毁和重建内部的事件监听和子组件;v-show只是简单的基于css切换。
  3. 编译条件:v-if是惰性的,如果初始条件为假,则什么也不做。只有在条件第一次变为真时才开始局部编译(编译被缓存;编译被缓存后,然后再切换的时候进行局部卸载)。 v-show是在任何条件下(首次条件是否为真)都被编译,然后被缓存,而且DOM元素保留;
  4. 性能消耗:v-if有更高的切换消耗;v-show有更高的初始渲染消耗。

使用场景

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

只能使用v-if

在实现递归组件的时候,必须使用 v-if,如果使用 v-show 会造成堆栈溢出:

/* 递归组件 */
<template>
  <div :class="[!notFirst && 'tree']">
    <Tree v-if="length > 0" :length="length-1" :notFirst="true"/>
    <Tree v-if="length > 0" :length="length-1" :notFirst="true"/>
  </div>
</template>
<script>
export default {
  name: "Tree",
  props: ["length", "notFirst"]
};
</script>
<style scoped>
.tree {
  position: relative;
  margin-top: 300px;
  margin-left: 100px;
  width: 100px;
  height: 100px;
  background: inherit;
}
div {
  background: #000;
  width: 1px;
  height: 70%;
  position: absolute;
  bottom: 100%;
  transform-origin: 50% 100%;
}
div > div:first-child {
  transform: rotate(-23deg);
}
div > div:last-child {
  transform: rotate(15deg);
}
</style>

如果这里使用v-show,会造成条件无法终止,也就会一直无限递归下去。最终会造成栈溢出:

只能使用 v-show

在表单中,需要隐藏一些输入框,但是在表单提交的时候,需要这些值:

/* form组件 */
<template>
  <div>
    <form ref="form" action="/" method='get'>
      <div v-show="type!='edit'">
        <label for="username">用户名:</label>
        <input type="text" name="username" v-model="username">
      </div>
      <div>
        <label for="password">密码:</label>
        <input type="text" name="password" v-model="password">
      </div>
      <button @click="submit">submit</button>
    </form>
  </div>
</template>
<script>
export default {
  data() {
    return {
      username: this.savedName,
      password: ''
    };
  },
  name: "VForm",
  props: ["type",'savedName'],
};
</script>
<template >
  <div>
      <VForm type="edit" savedName="princed"/>
  </div>
</template>
<script>
import VForm from "./form";
export default {
  components: {
    VForm
  },
};
</script>