v-if 和 v-show 有什么区别?
简化版
v-if 是条件渲染,条件为 false 时 DOM 不存在;v-show 是显示隐藏,DOM 一直存在,只切换 display。切换频繁用 v-show,条件很少变化或初始不需要渲染用 v-if。
详细版
v-if:
<div v-if="visible">内容</div>
条件 false 时组件和 DOM 会被销毁,重新变 true 时再创建。
v-show:
<div v-show="visible">内容</div>
元素一直渲染,只是通过 CSS 控制 display: none。
选择:
- 初始渲染成本敏感、权限控制、一次性条件:用
v-if。 - 频繁切换的 tab、弹层显示隐藏:用
v-show。
注意 v-show 不支持 template,也不能和 v-else 配合。
完整版教学
一、DOM 是否存在是本质区别
v-if 条件不满足时,节点不会出现在 DOM 中。对应组件也不会创建,生命周期钩子不会进入 mounted。
v-show 无论条件如何都会渲染,只是样式隐藏。所以它初始渲染成本更高,但切换成本低。
二、性能取舍
如果一个复杂组件大部分时间不显示,而且很少打开,v-if 更好,因为不用一开始就创建它。
如果一个面板频繁展开收起,v-show 更好,因为不用反复创建和销毁 DOM。
两者优化的是不同阶段:v-if 可以免掉初始为 false 的创建成本,v-show 则先支付创建成本来换取低廉的后续切换。组件越重、切换次数越多,这个取舍越需要用性能记录而不是凭标签判断。
三、生命周期影响
v-if 从 false 到 true,会重新创建子组件;从 true 到 false,会卸载子组件。里面的本地状态也会丢失。
v-show 不会销毁组件,本地状态会保留。这在表单、tab 内容里很重要。
四、和权限控制的关系
权限控制通常用 v-if,因为没有权限的内容不应该渲染出来。v-show 只是隐藏,用户仍可能在 DOM 中看到内容。
当然真正安全必须后端鉴权,前端隐藏只是体验层。
五、面试追问与工程落地
常见追问是“v-if 和 v-for 能不能放一起”。Vue 不推荐同一个元素上同时使用,因为优先级和可读性容易造成误解。更好的做法是先用 computed 过滤列表,再 v-for 渲染,或者外层 template 做条件控制。
还会问 v-if 切换是否会保留组件状态。默认不会。false 时组件被卸载,本地状态、DOM 状态、未持久化输入都会丢失。如果想隐藏但保留状态,使用 v-show 或 keep-alive,根据场景决定。
工程里权限控制、重型组件懒创建、一次性弹窗适合 v-if;频繁 tab 切换、下拉区域、简单显示隐藏适合 v-show。选择标准不是“哪个性能更好”,而是初始成本和切换成本哪个更重要。
六、用成本模型判断临界场景
v-if 是惰性条件分支:初始为 false 时连子树创建成本都不支付,切到 true 才挂载;每次真假切换可能涉及组件创建、DOM 插入、事件绑定和卸载清理。v-show 首次一定创建子树,之后主要切换元素内联 display,因此固定成本高、重复切换成本低。
总成本(示意)
v-if ≈ 首次命中创建成本 + 切换次数 × 创建/卸载成本
v-show ≈ 固定首次创建成本 + 切换次数 × 样式切换成本
假设重型面板创建约 20 ms、每次重建约 20 ms,而 display 切换约 0.1 ms:只打开 1 次时 v-if 约付 20 ms,v-show 首屏也先付 20 ms;切换 100 次时 v-if 的重复成本可能接近 2000 ms,v-show 的切换成本约 10 ms。数字只用于说明成本结构,真实结果必须以组件和设备测量为准。
| 维度 | v-if | v-show |
|---|---|---|
| false 时 DOM | 不存在 | 存在但 display: none |
| 初始 false 成本 | 低 | 仍创建子树 |
| 高频切换成本 | 创建/卸载较高 | 样式切换较低 |
| 本地状态 | 卸载后丢失 | 继续保留 |
<template> / v-else | 支持 | 不支持 |
权限场景用 v-if 只能减少前端展示,不能替代后端鉴权;已经发到浏览器的数据仍可能被用户读取。对于需要缓存多个动态组件状态的页面,KeepAlive 提供的是停用/激活而非普通 CSS 隐藏,也不能与 v-show 简单画等号。
<HeavyPanel v-if="created && visible" />
<Toolbar v-show="visible" />
如果重型面板首次很可能不打开,可以先用 v-if 延迟创建;但一旦还需要在首次创建后长期保留状态,就不能仅靠上面的双条件自动得到“创建一次、以后只隐藏”的语义,通常要把“是否已创建”和“当前是否可见”分开设计,或使用缓存组件。
还要区分视觉隐藏与可交互性。display: none 的元素不占布局且通常不进入可访问性树,但敏感数据已经存在于客户端;若只是用透明度或位移模拟隐藏,还可能保留焦点和点击区域,这已不是 v-show 的等价实现。
选择时同时估算“首次是否大概率出现、会切换多少次、状态是否要保留”,不要只背“频繁就 v-show”而忽略重型隐藏子树的首屏成本。
七、常见误区与追问
- 误区:v-show 为 false 时元素不会渲染。 元素已经创建,只是通过 display 样式隐藏,仍能在 DOM 中找到。
- 误区:v-if 一定比 v-show 性能好。 v-if 初始可省成本,但频繁切换会反复创建和卸载;应比较实际使用频率。
- 误区:v-if 可以承担真正的权限安全。 前端条件只能控制界面,敏感操作和数据必须由服务端鉴权。
- 追问:为什么 v-show 不支持 template? 它依赖给真实元素设置 display,template 本身不会渲染成可设置样式的 DOM 节点。
- 追问:v-if 切掉组件后状态还在吗? 默认组件会卸载,本地响应式状态和 DOM 状态丢失;需要保留应重新评估 v-show 或 KeepAlive。
- 追问:v-if 和 v-for 为什么不建议写在同一元素? Vue3 中 v-if 优先,表达式可能拿不到 v-for 作用域变量,也让过滤与渲染职责混乱。
- 追问:怎样选择首次隐藏但以后高频切换的重型面板? 需要结合首屏与后续交互目标,可能先延迟创建,再用状态缓存;不能只靠单条口诀决定。
八、加强记忆
v-if 是“有没有”,v-show 是“看不看”。少切换、需销毁用 v-if;频繁切换、保状态用 v-show。
最终选择要比较首建、重复切换和状态保留三项成本,权限安全则始终交给服务端。