Vue 的 v-if 和 v-show 有什么区别?频繁切换时应该怎么选?
下面是一段教学用的模拟面试。
🧑💻 面试官:v-if 和 v-show 怎么选?
🙋♂️ 我:经常切换用 v-show,不经常切换用 v-if。
🧑💻 面试官:一个组件里有计时器。用 v-show 把它隐藏,计时器也会停止吗?
🙋♂️ 我:不一定。它只是隐藏,组件还在。
🧑💻 面试官:那一个填到一半的表单,用 v-if 关闭再打开,为什么里面的数据可能没了?是不是所有表单都一定会丢?
“看不见”有两种做法:「没有创建这段组件树」,或者「组件还在,只是不显示」。
面试速答(60 秒版)
v-if 是条件渲染,条件不成立时不创建对应分支;已经创建后再变为 false,会卸载这段分支,之后重新满足条件时再创建。
v-show 则先渲染元素,主要通过切换 CSS 的 display 控制显示。因此,隐藏时 DOM 和组件实例通常仍然保留,组件内部状态不会因为这次隐藏自动重置。
所以,频繁切换、希望保留局部状态的轻量面板,可以考虑 v-show;首次不一定需要、创建成本较高且很少打开的区域,可以考虑 v-if。
但选择不能只看切换次数。隐藏后的订阅、计时器是否还运行,状态是否应该保留,以及关闭时是否需要释放资源,也需要一起判断。

知识点详解:同一个表单,关闭时到底发生了什么?
先让读者看到“存在”和“显示”的区别
假设页面中有一个设置面板,只有点开按钮时才看见。
用 v-if 时,初始条件为 false,Vue 不创建这个分支里的子组件。打开时,子组件开始自己的挂载过程;关闭时,对应组件卸载,相关 DOM 被移除。
用 v-show 时,元素从一开始就会渲染。关闭面板相当于把显示开关关掉,而不是把组件从页面结构中拆走。
Vue 条件渲染文档把 v-if 的切换描述为销毁、重建相关子组件,把 v-show 描述为 CSS 显示切换。这个区别解释了后面几种现象。
为什么 v-if 重新打开后,输入可能回到初始值?
假设表单子组件自己保存一个 ref,初始内容为空。用户输入了名字,关闭时子组件被卸载,再打开时创建的是一个新的实例,它会重新执行初始化,因此又从空字符串开始。
不过,这里必须补一个条件:数据保存在被卸载的子组件内部。
如果表单数据保存在始终存在的父组件或外部状态中,重新创建子组件时,仍然可以把保存的数据传回去。不能只看到 v-if,就断言所有数据都会丢。
所以,需要先追问状态存在哪里。组件实例销毁和数据被谁保存,并不是同一个判断。

隐藏组件,不等于暂停它的工作
假设子组件挂载时启动计时器,每秒更新一次数字。
使用 v-show 隐藏时,组件没有因此卸载,计时器也不会因为 display: none 自动取消。请求轮询、事件订阅和观察任务,同样不能仅靠“看不见了”来判断是否停下。
使用 v-if 时,如果组件确实被卸载,可以在卸载回调中释放这些资源。下面是 Vue 3 的 TypeScript 子组件示例:
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from "vue";
const ticks = ref(0);
let timer: ReturnType<typeof setInterval> | undefined;
onMounted(() => {
timer = setInterval(() => { ticks.value += 1; }, 1000);
});
onUnmounted(() => {
if (timer !== undefined) clearInterval(timer);
});
</script>
<template>
<p>运行次数:{{ ticks }}</p>
</template>
父组件用 v-if 切换这个子组件时,卸载回调会参与清理;父组件仅用 v-show 隐藏它时,不能指望这个回调执行。Vue 生命周期 API说明了这些回调的使用位置。
本题涉及 Vue 浏览器组件生命周期,没有可信的同款 Python 组件 API,因此不机械翻译这段代码。
如果业务要求“隐藏就停止,重新显示再启动”,可以让子组件接收可见状态,明确监听它并控制任务启停。使用 v-show 不是禁止清理,而是清理条件需要自己安排。

经常切换,是倾向,不是唯一的选型公式
一个小型筛选面板,用户频繁展开、收起,内部任务简单,保留输入也合理,v-show 往往比较方便。
另一个面板需要创建大量子组件,绝大多数用户不会打开。此时,v-if 可以避免初始就把它创建出来。
但假设面板隐藏后仍进行昂贵的后台计算,即使切换频繁,也不应仅凭“频繁”选 v-show。可以暂停后台任务、移出不该由显示层承担的工作,或者接受重建成本。
同样,想保留状态但又想卸载显示区域时,可以把数据放在外层。不要把“保留状态”与“必须保留整个组件实例”画等号。
两条语法边界,也经常会被追问
v-show 不支持用 template 元素把一组节点包成一个隐藏分支,也不能与 v-else 搭配成条件链。
v-if 可以配合 v-else-if、v-else,不过相邻关系要符合 Vue 的语法要求。这里不需要把指令大全背一遍,说明条件分支和显示切换不是同一套语法就够了。
另外,前端隐藏不构成权限保护。v-if 不渲染敏感按钮,也不能代替后端鉴权;接口返回的数据和执行权限仍要在服务端控制。
面试官继续追问
v-show 隐藏的元素还占布局空间吗?
通常不占,因为它主要通过 display: none 隐藏。但“没有占布局空间”并不说明 DOM 或组件实例不存在,也不说明后台任务已经停止。
关闭表单就应该清空数据,选哪个?
可以让 v-if 的实例重建帮助重置局部状态,也可以明确执行重置逻辑。先定义清空范围,不要依赖组件里碰巧保存在哪里的状态。
想复用组件实例,是不是必须改成 v-show?
不是。还可以根据场景使用 KeepAlive 等机制,但它的缓存与激活生命周期是另一套语义。先判断当前需要隐藏 DOM、卸载组件还是缓存实例,不把三个词混用。
面试速记卡
- v-if:条件不成立不创建,切换会卸载、重新创建分支。
- v-show:元素仍保留,主要切换 CSS display。
- 状态:是否丢失取决于谁保存,不只取决于哪个指令。
- 资源:隐藏不会自动停止计时器和订阅,要明确清理条件。
- 选型:一起看初始成本、切换成本、状态和后台工作。
公司面试真题
这道题暂未收录可核验的公司真题来源。你可以先阅读本文解析,或浏览已收录的公司面试真题。
浏览公司面试真题 →