Vue 中的 v-show 和 v-if 怎么理解?

一、v-show 与 v-if 的共同点

我们都知道在 vue 中 v-show 与 v-if 的作用效果是相同的(不含 v-else),都能控制元素在页面是否显示。

在用法上也是相同的:

<Modal v-show="isShow" />
<Modal v-if="isShow" />

二、v-show 与 v-if 的区别

维度v-showv-if
控制手段设置 display: none,DOM 元素依旧还在将 DOM 元素整个添加或删除
编译过程只是简单的基于 CSS 切换切换有一个局部编译/卸载的过程,会销毁和重建内部的事件监听和子组件
编译条件元素总是会被渲染真正的条件渲染,确保条件块内的事件监听和子组件被适当地销毁和重建;条件为假时什么都不做
性能消耗更高的初始渲染消耗更高的切换消耗

三、v-show 与 v-if 原理分析

v-show 原理

不管初始条件是什么,元素总是会被渲染。

// https://github.com/vuejs/vue-next/blob/3cd30c5245da0733f9eb6f29d220f39c46518162/packages/runtime-dom/src/directives/vShow.ts
export const vShow: ObjectDirective<VShowElement> = {
  beforeMount(el, { value }, { transition }) {
    el._vod = el.style.display === 'none' ? '' : el.style.display
    if (transition && value) {
      transition.beforeEnter(el)
    } else {
      setDisplay(el, value)
    }
  },
  mounted(el, { value }, { transition }) {
    if (transition && value) {
      transition.enter(el)
    }
  },
  updated(el, { value, oldValue }, { transition }) {
    // ...
  },
  beforeUnmount(el, { value }) {
    setDisplay(el, value)
  }
}

有 transition 就执行 transition,没有就直接设置 display 属性。

v-if 原理

v-if 在实现上比 v-show 要复杂得多,因为还有 else / else-if 等条件需要处理。返回一个 node 节点,render 函数通过表达式的值来决定是否生成 DOM:

// https://github.com/vuejs/vue-next/blob/cdc9f336fd/packages/compiler-core/src/transforms/vIf.ts
export const transformIf = createStructuralDirectiveTransform(
  /^(if|else|else-if)$/,
  (node, dir, context) => {
    return processIf(node, dir, context, (ifNode, branch, isRoot) => {
      // ...
      return () => {
        if (isRoot) {
          ifNode.codegenNode = createCodegenNodeForBranch(
            branch,
            key,
            context
          ) as IfConditionalExpression
        } else {
          const parentCondition = getParentCondition(ifNode.codegenNode!)
          parentCondition.alternate = createCodegenNodeForBranch(
            branch,
            key + ifNode.branches.length - 1,
            context
          )
        }
      }
    })
  }
)

四、v-show 与 v-if 的使用场景

  • v-if 与 v-show 都能控制 DOM 元素在页面的显示。
  • v-if 相比 v-show 开销更大(直接操作 DOM 节点增加与删除)。
  • 如果需要非常频繁地切换,则使用 v-show 较好。
  • 如果在运行时条件很少改变,则使用 v-if 较好。

来源整理自:vue3js.cn 面试官系列