【vue篇】Vue 条件渲染终极对决:v-if vs v-show 深度解析

115 阅读3分钟

在 Vue 开发中,v-ifv-show 都能实现“条件显示”,但它们的底层机制、性能表现、适用场景截然不同。

选错一个,可能导致:

  • 页面卡顿(频繁切换 v-if
  • 首屏加载变慢(大量 v-show
  • 内存泄漏(组件未销毁)

本文将从 5 个维度全面对比 v-ifv-show,助你做出最优选择。


一、核心区别速览

对比维度v-ifv-show
控制手段动态添加/删除 DOM修改 display 样式
编译过程局部编译/卸载简单 CSS 切换
初始渲染惰性编译(条件为真时才编译)无论真假,始终编译
切换性能❌ 消耗高(重建组件)✅ 消耗低(仅样式)
初始性能✅ 消耗低(条件为假时跳过)❌ 消耗高(始终渲染)
适用场景条件极少改变频繁切换

二、底层原理深度解析

1️⃣ v-if:DOM 的“销毁与重建”大师

📌 工作流程

<div v-if="isVisible">我是内容</div>
  • isVisible = true

    1. 创建 DOM 节点;
    2. 插入到父元素;
    3. 触发 mounted 生命周期。
  • isVisible = false

    1. 移除 DOM 节点;
    2. 销毁组件实例;
    3. 触发 beforeDestroydestroyed

📌 编译特性:惰性编译

data() {
  return {
    isVisible: false
  };
}
  • ❌ 初始渲染时,v-if 内容完全不编译
  • ✅ 只有当 isVisible 第一次变为 true 时,才开始编译和渲染。

💡 类似“按需加载”。

📌 组件状态

  • ❌ 状态不保留:每次切换都会丢失 data、事件监听器、子组件状态;
  • ✅ 适合“一次性”或“独立”组件。

2️⃣ v-show:CSS 的“显示开关”

📌 工作流程

<div v-show="isVisible">我是内容</div>
  • isVisible = truedisplay: block(或原值);
  • isVisible = falsedisplay: none

📌 编译特性:始终编译

  • ✅ 无论 isVisible 初始值是 true 还是 false,内容都会被编译;
  • ✅ DOM 节点始终存在,只是“看不见”;
  • ✅ 组件实例、事件监听器、子组件全部保留

📌 性能表现

  • ✅ 切换极快:浏览器对 display 的修改高度优化;
  • ❌ 占用内存:即使隐藏,组件仍在内存中;
  • ✅ 保留状态:非常适合表单、编辑器等需要“记忆”的场景。

三、性能对比实战

📊 场景 1:首屏加载性能

<template>
  <!-- 首屏不需要的模块 -->
  <div v-if="showSettings">设置面板</div>
  <div v-show="showHelp">帮助文档</div>
</template>
方案首屏 DOM 节点数内存占用推荐
v-if减少✅ 首屏快
v-show不变❌ 拖慢首屏

结论:首屏隐藏内容,优先用 v-if


📊 场景 2:频繁切换的标签页

<template>
  <div>
    <button @click="activeTab = 'home'">首页</button>
    <button @click="activeTab = 'profile'">个人</button>
    
    <Home v-if="activeTab === 'home'" />
    <Profile v-if="activeTab === 'profile'" />
    
    <!-- 或 -->
    <Home v-show="activeTab === 'home'" />
    <Profile v-show="activeTab === 'profile'" />
  </div>
</template>
方案切换速度组件状态推荐
v-if❌ 慢(重建)❌ 丢失❌ 不推荐
v-show✅ 极快✅ 保留✅ 推荐

结论:频繁切换,用 v-show


四、生命周期影响对比

生命周期v-ifv-show
created每次显示都触发仅首次触发
mounted每次显示都触发仅首次触发
beforeDestroy隐藏时触发❌ 不触发
destroyed隐藏时触发❌ 不触发
activated❌ 不适用✅ 始终可用

💡 v-show 的组件永远不会被销毁,因此 destroyed 永远不会执行。


五、内存与事件监听器

v-show 的潜在风险

export default {
  mounted() {
    window.addEventListener('resize', this.handleResize);
  },
  beforeDestroy() {
    window.removeEventListener('resize', this.handleResize);
  }
}
  • v-if:隐藏时自动移除事件监听;
  • v-show:即使隐藏,事件监听器依然存在,可能导致:
    • 内存泄漏;
    • 多次绑定(如果逻辑不当)。

💡 使用 v-show 时,务必手动清理全局事件。


六、最佳实践指南

✅ 选择决策树

你的组件需要频繁切换吗?
├── 是 → 使用 v-show
└── 否
    ├── 首屏不需要显示?
    │   ├── 是 → 使用 v-if(减少首屏负载)
    │   └── 否 → 两者皆可,推荐 v-show(避免重复渲染)
    └── 是否包含重型组件(如图表、编辑器)?
        ├── 是 → v-if(避免初始化开销)
        └── 否 → v-show

✅ 推荐组合使用

<!-- 首次加载用 v-if,之后用 v-show -->
<div v-if="loaded" v-show="isVisible">
  重型内容
</div>
data() {
  return {
    loaded: false,
    isVisible: false
  };
},
mounted() {
  // 数据加载完成后标记 loaded
  api.getData().then(() => {
    this.loaded = true;
    this.isVisible = true;
  });
}

💡 结语

“v-if 是‘开关’,v-show 是‘窗帘’。”

  • v-if:适合条件稳定首屏隐藏重型组件
  • v-show:适合频繁切换轻量组件需保留状态

记住:

“少用 v-if 切换,多用 v-show 显示。”

掌握这个原则,你的 Vue 应用将更加流畅、高效、稳定