05Vue 3 条件渲染详解
一、核心概念
条件渲染是指根据特定条件动态控制 DOM 元素的显示与隐藏。Vue 3 提供了多种方式来实现条件渲染。
二、主要指令
1. v-if / v-else-if / v-else
基本用法:
<template>
<div>
<!-- v-if -->
<p v-if="isVisible">这段文字会条件显示</p>
<!-- v-else-if 和 v-else -->
<div v-if="type === 'A'">显示 A</div>
<div v-else-if="type === 'B'">显示 B</div>
<div v-else>显示其他</div>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
const type = ref('A')
</script>
特点:
-
真正的条件渲染:元素在条件为假时不会被渲染到 DOM 中
-
切换开销较大:每次切换都会创建/销毁元素和组件
-
适用于不频繁切换的场景
2. v-show
<template>
<div>
<p v-show="isVisible">这段文字会条件显示/隐藏</p>
</div>
</template>
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
特点:
-
通过 CSS 的
display: none控制显示/隐藏 -
元素始终会被渲染并保留在 DOM 中
-
切换开销较小
-
适用于频繁切换的场景
三、v-if vs v-show 对比

四、高级用法
1. 在 <template> 上使用 v-if
<template>
<!-- 包裹多个元素 -->
<template v-if="showSection">
<h2>标题</h2>
<p>内容...</p>
<p>更多内容...</p>
</template>
</template>
2. 条件渲染组合示例
<template>
<div>
<!-- 登录状态判断 -->
<div v-if="isLoading">加载中...</div>
<div v-else-if="error">加载失败: {{ error }}</div>
<div v-else-if="data.length === 0">暂无数据</div>
<ul v-else>
<li v-for="item in data" :key="item.id">{{ item.name }}</li>
</ul>
<!-- 根据用户角色显示不同内容 -->
<div v-if="user.role === 'admin'">
<button>管理设置</button>
<button>删除用户</button>
</div>
<div v-else-if="user.role === 'editor'">
<button>编辑内容</button>
</div>
<div v-else>
<button>查看内容</button>
</div>
<!-- 结合计算属性 -->
<div v-if="shouldShowAdvancedOptions">
高级选项...
</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const isLoading = ref(false)
const error = ref(null)
const data = ref([])
const user = ref({ role: 'admin' })
// 使用计算属性处理复杂条件
const shouldShowAdvancedOptions = computed(() => {
return user.value.role === 'admin' && data.value.length > 10
})
</script>
3. 与 v-for 一起使用
<template>
<ul>
<!-- 不推荐:v-if 和 v-for 在同一元素 -->
<!-- <li v-for="item in items" v-if="item.isActive"> {{ item.name }} </li> -->
<!-- 推荐:使用 template 包裹 -->
<template v-for="item in items" :key="item.id">
<li v-if="item.isActive">{{ item.name }}</li>
</template>
<!-- 或者使用计算属性过滤 -->
<li v-for="item in activeItems" :key="item.id">{{ item.name }}</li>
</ul>
</template>
<script setup>
import { ref, computed } from 'vue'
const items = ref([
{ id: 1, name: 'Item 1', isActive: true },
{ id: 2, name: 'Item 2', isActive: false },
{ id: 3, name: 'Item 3', isActive: true }
])
// 使用计算属性过滤
const activeItems = computed(() => items.value.filter(item => item.isActive))
</script>
五、性能优化技巧
1. 使用 key 管理可复用元素
<template>
<div>
<!-- 添加 key 强制重新渲染 -->
<div v-if="loginType === 'username'" key="username">
<label>用户名</label>
<input placeholder="请输入用户名">
</div>
<div v-else key="email">
<label>邮箱</label>
<input placeholder="请输入邮箱">
</div>
<button @click="toggleLoginType">切换登录方式</button>
</div>
</template>
<script setup>
import { ref } from 'vue'
const loginType = ref('username')
const toggleLoginType = () => {
loginType.value = loginType.value === 'username' ? 'email' : 'username'
}
</script>
2. 懒加载组件
<template>
<div>
<button @click="showComponent = !showComponent">切换组件</button>
<!-- 使用 v-if 实现懒加载 -->
<UserProfile v-if="showComponent" />
<!-- 或者使用 Suspense + defineAsyncComponent -->
<Suspense>
<template #default>
<AsyncComponent v-if="showComponent" />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</div>
</template>
<script setup>
import { ref, defineAsyncComponent } from 'vue'
const showComponent = ref(false)
// 异步组件
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
</script>
六、实际应用示例
<template>
<div class="user-dashboard">
<!-- 权限控制 -->
<AdminPanel v-if="user.role === 'admin'" />
<!-- 功能开关 -->
<BetaFeatures v-show="features.betaEnabled" />
<!-- 空状态处理 -->
<div v-if="tasks.length === 0" class="empty-state">
<p>还没有任务,快去创建一个吧!</p>
<button @click="createTask">创建任务</button>
</div>
<!-- 骨架屏 -->
<div v-else-if="loading" class="skeleton">
<div class="skeleton-item"></div>
<div class="skeleton-item"></div>
<div class="skeleton-item"></div>
</div>
<!-- 正常显示 -->
<TaskList v-else :tasks="tasks" />
<!-- 响应式显示 -->
<MobileMenu v-show="isMobileScreen" />
<DesktopMenu v-show="!isMobileScreen" />
</div>
</template>
<script setup>
import { ref, computed, onMounted, onUnmounted } from 'vue'
import AdminPanel from './AdminPanel.vue'
import BetaFeatures from './BetaFeatures.vue'
import TaskList from './TaskList.vue'
import MobileMenu from './MobileMenu.vue'
import DesktopMenu from './DesktopMenu.vue'
const user = ref({ role: 'user' })
const features = ref({ betaEnabled: true })
const tasks = ref([])
const loading = ref(true)
const windowWidth = ref(window.innerWidth)
const isMobileScreen = computed(() => windowWidth.value < 768)
const updateWindowWidth = () => {
windowWidth.value = window.innerWidth
}
onMounted(() => {
window.addEventListener('resize', updateWindowWidth)
fetchTasks()
})
onUnmounted(() => {
window.removeEventListener('resize', updateWindowWidth)
})
const fetchTasks = async () => {
loading.value = true
try {
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 1000))
tasks.value = [
{ id: 1, title: '学习 Vue 3', completed: false },
{ id: 2, title: '完成项目', completed: true }
]
} finally {
loading.value = false
}
}
const createTask = () => {
// 创建任务逻辑
}
</script>
<style scoped>
.empty-state {
text-align: center;
padding: 2rem;
}
.skeleton-item {
height: 20px;
background: #eee;
margin: 10px 0;
border-radius: 4px;
animation: pulse 1.5s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
</style>
七、最佳实践
-
选择合适的指令:
-
使用
v-if当元素不频繁切换或初始条件为假 -
使用
v-show当元素需要频繁切换显示状态
-
-
避免
v-if和v-for同时使用:-
优先使用计算属性过滤数据
-
或使用
<template>包裹
-
-
复杂条件使用计算属性:
-
提高模板可读性
-
便于复用和维护
-
-
考虑可访问性:
-
使用
v-show时注意屏幕阅读器的行为 -
确保隐藏内容不会影响可访问性
-
-
性能监控:
-
大量
v-if切换时注意性能影响 -
必要时使用虚拟滚动或分页
-
通过合理使用条件渲染,可以创建更加动态、高效和用户友好的 Vue 应用。

浙公网安备 33010602011771号