Skip to content

v-if 的本质

v-if 是 Vue 中最典型的结构性指令之一。

如果只看表面,它像是在“控制一个元素显示不显示”;但更准确地说:

v-if 的本质,是在编译阶段把模板分支改写成不同的渲染分支,然后由运行时根据条件选择创建、更新或卸载对应节点。

也就是说,它不是简单的“隐藏元素”,而是决定这部分视图是否真正参与渲染树。

先看最基础的写法

html
<div v-if="isVisible">Hello World</div>

它的语义是:

  • isVisible === true 时,这个节点存在
  • isVisible === false 时,这个节点不存在

这里的“不存在”很关键。
它和 v-show 的思路完全不同。

编译后的本质

这段模板大致会被编译成类似这样的渲染逻辑:

js
function render() {
  return this.isVisible
    ? h('div', null, 'Hello World')
    : null
}

在 Vue 实际产物里,通常会更接近:

js
return _ctx.isVisible
  ? (_openBlock(), _createElementBlock('div', null, 'Hello World'))
  : _createCommentVNode('v-if', true)

这里最重要的判断是:

  • v-if 在运行时不再以“指令字符串”存在
  • 编译器已经把它改写成普通的条件分支

所以它是非常典型的结构性编译转换

为什么说它是“结构性”指令

因为它改变的不是某个 prop,也不是某个事件处理器,而是整棵模板结构。

v-if 时,编译器需要决定:

  • 当前分支渲染哪个节点
  • 不满足条件时是输出注释占位,还是切换到其他分支
  • v-else-if / v-else 怎样和前一个分支合并成完整逻辑

这已经不是“补一个属性”能解决的事情了,而是模板 AST 层面的重写。

它和虚拟 DOM 的关系

每次条件变化时,Vue 会重新执行渲染逻辑,得到新的 VNode 树。

如果条件从 false 变成 true

  • 会新增对应 VNode
  • 运行时把它挂到真实 DOM

如果条件从 true 变成 false

  • 这部分 VNode 会消失
  • 运行时把对应真实 DOM 卸载掉

所以 v-if 的本质不是“切换 CSS”,而是让节点真正进入或退出渲染结果。

它和响应式系统的关系

v-if 本身不提供响应式,它只是读取一个响应式条件表达式。

isVisible 变化时:

  1. 响应式系统触发组件更新
  2. 渲染函数重新执行
  3. 条件分支重新判断
  4. 运行时根据新旧结果更新 DOM

所以可以把它理解为:

  • 响应式系统负责“通知条件变了”
  • v-if 负责“决定这一块还渲不渲”

v-if 和 v-show 的核心差异

这是最需要记清的一组对比:

v-if

  • 控制“是否渲染”
  • 会创建、卸载节点
  • 更适合低频切换

v-show

  • 控制“是否显示”
  • DOM 始终存在
  • 通常通过 display: none 切换
  • 更适合高频显示/隐藏

所以判断标准不是“哪个更高级”,而是:

  • 你要不要真的卸载这块内容
  • 切换频率高不高

对组件生命周期的影响

如果 v-if 控制的是组件,而不是普通元素,那么它不仅会影响 DOM,还会影响组件生命周期。

当条件为 true

  • 组件被创建
  • 挂载
  • 触发 onMounted / mounted

当条件变为 false

  • 组件卸载
  • 触发 onBeforeUnmount / beforeUnmount
  • 触发 onUnmounted / unmounted

当条件再次变为 true

  • 是一次重新创建,不是简单恢复显示

这也是为什么有些带状态组件放在 v-if 下时,你会感觉“状态被重置了”。

一句话判断它的本质

如果一个能力最终编译成普通条件分支,并决定节点是否真的进入渲染树,那它就更接近 v-if 这种结构性编译能力,而不是运行时指令。

总结

特性说明
编译本质v-if 被改写成条件分支渲染逻辑
主要机制结构性编译转换 + 运行时挂载/卸载
v-show 区别v-if 控制是否存在,v-show 控制是否显示
对组件影响会触发完整挂载与卸载生命周期
适用场景低频切换、初始不一定渲染的内容

Released under the CC BY-NC-SA 4.0 License.