Vue:条件渲染 (Conditional Rendering)
1. 核心指令:v-if
作用:用于条件性地渲染一块内容。这块内容只会在指令的表达式返回真值 (truthy value) 时才被渲染和保留在 DOM 中。
语法:
<h1 v-if="awesome">Vue is awesome!</h1>
工作机制:
当
awesome
为真值时,<h1>
元素会被创建并插入到 DOM 中。当
awesome
变为假值时,Vue 会销毁该元素及其内部的事件监听器和子组件(触发相应的生命周期钩子)。当
awesome
再次变为真值时,Vue 会重新创建该元素及其内容(再次触发生命周期钩子)。
特点:是“真正”的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件被正确地销毁和重建。
2. 辅助指令:v-else
作用:为 v-if
添加一个“else 区块”。必须紧跟在 v-if
或 v-else-if
元素后面,否则它将无法被识别。
语法:
<button @click="awesome = !awesome">Toggle</button><h1 v-if="awesome">Vue is awesome!</h1>
<h1 v-else>Oh no 😢</h1>
注意:v-else
不需要任何表达式。
3. 辅助指令:v-else-if
作用:提供相当于 v-if
的“else if 区块”。可以连续多次重复使用,用于实现多个分支的条件判断。
语法:
<div v-if="type === 'A'">A
</div>
<div v-else-if="type === 'B'">B
</div>
<div v-else-if="type === 'C'">C
</div>
<div v-else>Not A/B/C
</div>
注意:和 v-else
类似,一个使用 v-else-if
的元素必须紧跟在一个 v-if
或一个 v-else-if
元素后面。
4. 在 <template>
上使用 v-if
问题:v-if
必须依附于单个元素。如果想切换多个元素,包裹一个 div 有时会破坏 HTML 结构。
解决方案:可以在一个 <template>
元素上使用 v-if
。<template>
是一个不可见的包装器元素,最终的渲染结果不会包含它。
语法:
<template v-if="ok"><h1>Title</h1><p>Paragraph 1</p><p>Paragraph 2</p>
</template>
注意:v-else
和 v-else-if
同样可以在 <template>
上使用。
5. 替代指令:v-show
作用:另一个用于按条件显示一个元素的指令。元素始终会被渲染并保留在 DOM 中,v-show
只是简单地切换该元素的 CSS display
属性。
语法:
<h1 v-show="ok">Hello!</h1>
限制:
不支持在
<template>
元素上使用。不能和
v-else
搭配使用。
6. v-if
vs. v-show
核心对比
特性 | v-if | v-show |
---|---|---|
工作机制 | 条件性地渲染/销毁元素 | 始终渲染,仅切换 CSS display 属性 |
编译/渲染 | 惰性的:初始为 false 则不编译 | 无论条件如何,初始都会编译 |
DOM 操作 | 操作 DOM 节点的添加和移除 | 仅操作 CSS 样式 |
性能开销 | 更高的切换开销(尤其是初始为 false 时) | 更高的初始渲染开销(无论是否显示都要渲染) |
适用场景 | 运行时条件很少改变,或需要避免初始渲染 | 需要非常频繁切换的场景 |
选择策略流程图
7. 重要注意事项
v-if
与 v-for
的优先级
规则:当 v-if
和 v-for
同时用于同一个元素时,v-if
会首先被执行。
强烈建议:不要在同一元素上使用这两个指令。可以通过以下方式解决:
使用
<template>
包装:将v-for
放在<template>
上,v-if
放在内部元素上。使用计算属性:预先通过计算属性过滤列表,避免同时需要
v-if
和v-for
。
示例 (不推荐):
<!-- 不推荐的做法 -->
<li v-for="todo in todos" v-if="!todo.isComplete">{{ todo.name }}
</li>
示例 (推荐):
<!-- 推荐做法 1: 使用 <template> -->
<template v-for="todo in todos"><li v-if="!todo.isComplete">{{ todo.name }}</li>
</template><!-- 推荐做法 2: 使用计算属性 -->
<li v-for="todo in incompleteTodos">{{ todo.name }}
</li>
// ...
computed: {incompleteTodos() {return this.todos.filter(todo => !todo.isComplete);}
}
8. 总结
v-if
、v-else-if
、v-else
是一套用于实现条件块渲染/销毁的指令链,它们控制的是元素是否存在於 DOM 中。v-show
是一个独立的指令,它通过 CSS 控制元素的显示与隐藏,元素始终存在于 DOM 中。选择
v-if
还是v-show
取决于你的具体需求:需要频繁切换(如 tabs 切换)? ->
v-show
条件在运行时很少改变,或希望减少初始负载? ->
v-if
绝对避免在同一个元素上同时使用
v-if
和v-for
。如果需要,请使用<template>
标签或计算属性来拆分逻辑。使用
<template>
标签可以对多个元素进行分组条件渲染,而无需引入多余的 DOM 元素。