从编译结果看v-if与v-show

398 阅读2分钟

说到v-ifv-show的区别,你或许会很自然的就会说出, v-if会重新生成dom, v-show只是在切换css属性display,dom还是存在的...

这确实是两者一个重要的区别, 以下是vue官方文档中的描述:

v-if 是“真实的”按条件渲染,因为它确保了在切换时,条件区块内的事件监听器和子组件都会被销毁与重建, 如果在初次渲染时条件值为 false,则不会做任何事。条件区块只有当条件首次变为 true 时才被渲染。v-if可以与v-else、v-else-if配合使用.

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

从以下的demo中可以直观的看到两者的区别:

  • 初始条件为false, v-if的组件不会初始化, v-show的组件会
  • 切换v-if会导致组件挂载/卸载, 切换v-show不会
// template
<div id="app">
  <button @click="show = !show">{{ show ? 'Hide' : 'Show' }} Child Component</button>
  <hr>
<!--   <child-component v-if="show"></child-component> -->
  <child-component v-show="show"></child-component>
</div>

// js
Vue.component('child-component', {
  template: '<div>Child Component</div>',
  created() {
    console.log('Child Component created');
  },
  mounted() {
    console.log('Child Component mounted');
  },
  beforeDestroy() {
    console.log('Child Component beforeDestroy');
  },
  destroyed() {
    console.log('Child Component destroyed');
  }
});

new Vue({
  el: '#app',
  data: {
    show: false
  },
  created() {
    console.log('Parent Component created');
  },
  mounted() {
    console.log('Parent Component mounted');
  },
  beforeDestroy() {
    console.log('Parent Component beforeDestroy');
  },
  destroyed() {
    console.log('Parent Component destroyed');
  }
});

但我们要更进一步来看看两者编译后的区别. 链接:

v-if

<!-- 模板 -->
<li v-if="show">11</li>
<li v-else>22</li>
// 编译后
function render() {
  with(this) {
    return (show) ? _c('li', [_v("11")]) : _c('li', [_v("22")])
  }
}

v-show

<!-- 模板 -->
<li v-show="show">11</li>
// 编译后
function render() {
  with(this) {
    return _c('li', {
      directives: [{
        name: "show",
        rawName: "v-show",
        value: (show),
        expression: "show"
      }]
    }, [_v("11")])
  }
}
  • _c 指的是 createElement,用于创建组件节点
  • _v 是用来创建文本 VNode

也就是说v-if 在生成 VNode 前就已经在模板编译阶段进行了判断. 而 v-show 也是在编译时解析,只不过在 v-if 在编译时就确定了渲染元素,而v-show在运行时根据条件进行显示和隐藏。

v-show, 很明显是一个指令,与我们在render 函数中写指令是一样的,但是这样来看 v-if 肯定是一个语法糖,因为它并不是真正意义上的指令。

总结

我们能知道v-ifv-show的区别至少有三个方面:
1、初始条件为false, 绑定的组件是否会初始化;
2、切换时是否会导致组件挂载/卸载
3、编译结果的区别,以及内部是否是用自定义指令来实现的;