Vue.js 条件渲染
v-if 指令
v-if 指令用于条件性地渲染元素。当条件为真时,元素会被渲染;为假时,元素不会被渲染到 DOM 中。
基本用法
vue
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
<template>
<div>
<button @click="isVisible = !isVisible">切换显示</button>
<p v-if="isVisible">这段文字可以被切换显示</p>
</div>
</template>v-else
v-else 必须紧跟在 v-if 或 v-else-if 后面:
vue
<script setup>
import { ref } from 'vue'
const awesome = ref(true)
</script>
<template>
<div>
<button @click="awesome = !awesome">切换</button>
<h1 v-if="awesome">Vue 很棒!</h1>
<h1 v-else>哦不😢</h1>
</div>
</template>v-else-if
vue
<script setup>
import { ref } from 'vue'
const type = ref('A')
</script>
<template>
<div>
<select v-model="type">
<option>A</option>
<option>B</option>
<option>C</option>
<option>D</option>
</select>
<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>其他类型</div>
</div>
</template>在 template 上使用 v-if
当需要切换多个元素时,可以在 <template> 上使用 v-if:
vue
<script setup>
import { ref } from 'vue'
const showDetails = ref(false)
</script>
<template>
<div>
<button @click="showDetails = !showDetails">
{{ showDetails ? '隐藏' : '显示' }}详情
</button>
<template v-if="showDetails">
<h3>详细信息</h3>
<p>这是第一段详情</p>
<p>这是第二段详情</p>
<p>这是第三段详情</p>
</template>
</div>
</template>v-show 指令
v-show 也用于条件性地显示元素,但它只是切换元素的 CSS display 属性。
vue
<script setup>
import { ref } from 'vue'
const isVisible = ref(true)
</script>
<template>
<div>
<button @click="isVisible = !isVisible">切换显示</button>
<p v-show="isVisible">这段文字使用 v-show 切换</p>
</div>
</template>v-if vs v-show
区别
| 特性 | v-if | v-show |
|---|---|---|
| 渲染方式 | 条件性渲染(真正的条件渲染) | 始终渲染,只切换 display |
| 切换开销 | 较高(销毁和重建) | 较低(只改变 CSS) |
| 初始渲染开销 | 较低(条件为假时不渲染) | 较高(始终渲染) |
| 适用场景 | 条件很少改变 | 频繁切换 |
选择建议
vue
<script setup>
import { ref } from 'vue'
const frequentToggle = ref(true)
const rareToggle = ref(true)
</script>
<template>
<div>
<!-- 频繁切换,使用 v-show -->
<button @click="frequentToggle = !frequentToggle">频繁切换</button>
<p v-show="frequentToggle">使用 v-show(频繁切换)</p>
<!-- 很少改变,使用 v-if -->
<button @click="rareToggle = !rareToggle">很少切换</button>
<p v-if="rareToggle">使用 v-if(很少改变)</p>
</div>
</template>实战示例:用户登录状态
vue
<script setup>
import { ref } from 'vue'
const isLoggedIn = ref(false)
const user = ref({
name: '张三',
avatar: 'https://via.placeholder.com/50',
role: 'admin'
})
function login() {
isLoggedIn.value = true
}
function logout() {
isLoggedIn.value = false
}
</script>
<template>
<div class="header">
<div v-if="isLoggedIn" class="user-info">
<img :src="user.avatar" :alt="user.name" class="avatar" />
<span>欢迎,{{ user.name }}</span>
<span v-if="user.role === 'admin'" class="badge">管理员</span>
<button @click="logout">退出</button>
</div>
<div v-else class="login-prompt">
<p>您还未登录</p>
<button @click="login">登录</button>
</div>
</div>
</template>
<style scoped>
.header {
padding: 20px;
background-color: #f5f5f5;
border-radius: 8px;
}
.user-info {
display: flex;
align-items: center;
gap: 10px;
}
.avatar {
width: 50px;
height: 50px;
border-radius: 50%;
}
.badge {
background-color: #42b983;
color: white;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
}
.login-prompt {
text-align: center;
}
button {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #35a372;
}
</style>实战示例:加载状态
vue
<script setup>
import { ref, onMounted } from 'vue'
const isLoading = ref(true)
const hasError = ref(false)
const data = ref(null)
async function fetchData() {
isLoading.value = true
hasError.value = false
try {
// 模拟 API 调用
await new Promise(resolve => setTimeout(resolve, 2000))
data.value = {
title: '文章标题',
content: '这是文章内容...'
}
} catch (error) {
hasError.value = true
} finally {
isLoading.value = false
}
}
onMounted(() => {
fetchData()
})
</script>
<template>
<div class="container">
<!-- 加载中 -->
<div v-if="isLoading" class="loading">
<div class="spinner"></div>
<p>加载中...</p>
</div>
<!-- 错误状态 -->
<div v-else-if="hasError" class="error">
<p>❌ 加载失败</p>
<button @click="fetchData">重试</button>
</div>
<!-- 成功加载 -->
<div v-else class="content">
<h2>{{ data.title }}</h2>
<p>{{ data.content }}</p>
<button @click="fetchData">刷新</button>
</div>
</div>
</template>
<style scoped>
.container {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.loading {
text-align: center;
padding: 40px;
}
.spinner {
width: 40px;
height: 40px;
margin: 0 auto 20px;
border: 4px solid #f3f3f3;
border-top: 4px solid #42b983;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error {
text-align: center;
padding: 40px;
color: #f56c6c;
}
.content {
padding: 20px;
}
button {
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
margin-top: 10px;
}
button:hover {
background-color: #35a372;
}
</style>实战示例:权限控制
vue
<script setup>
import { ref, computed } from 'vue'
const currentUser = ref({
name: '张三',
role: 'user', // 'admin', 'user', 'guest'
permissions: ['read', 'write']
})
const isAdmin = computed(() => currentUser.value.role === 'admin')
const canWrite = computed(() => currentUser.value.permissions.includes('write'))
const canDelete = computed(() => currentUser.value.permissions.includes('delete'))
function changeRole(role) {
currentUser.value.role = role
if (role === 'admin') {
currentUser.value.permissions = ['read', 'write', 'delete']
} else if (role === 'user') {
currentUser.value.permissions = ['read', 'write']
} else {
currentUser.value.permissions = ['read']
}
}
</script>
<template>
<div class="permission-demo">
<h3>当前用户:{{ currentUser.name }} ({{ currentUser.role }})</h3>
<div class="role-switcher">
<button @click="changeRole('admin')">切换为管理员</button>
<button @click="changeRole('user')">切换为普通用户</button>
<button @click="changeRole('guest')">切换为访客</button>
</div>
<div class="actions">
<button>查看(所有人可见)</button>
<button v-if="canWrite">
编辑(需要写权限)
</button>
<button v-if="canDelete">
删除(需要删除权限)
</button>
<div v-if="isAdmin" class="admin-panel">
<h4>🔧 管理员面板</h4>
<p>只有管理员可以看到这个面板</p>
</div>
</div>
</div>
</template>
<style scoped>
.permission-demo {
max-width: 600px;
margin: 20px auto;
padding: 20px;
border: 1px solid #ddd;
border-radius: 8px;
}
.role-switcher {
margin: 20px 0;
display: flex;
gap: 10px;
}
.actions {
margin-top: 20px;
}
.actions button {
margin-right: 10px;
margin-bottom: 10px;
padding: 8px 16px;
background-color: #42b983;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.admin-panel {
margin-top: 20px;
padding: 15px;
background-color: #fff3cd;
border: 1px solid #ffc107;
border-radius: 4px;
}
</style>总结
v-if是真正的条件渲染,元素会被销毁和重建v-show只是切换 CSS display 属性v-if适合条件很少改变的场景v-show适合频繁切换的场景- 可以使用
v-else和v-else-if创建更复杂的条件逻辑
下一步
接下来学习 列表渲染,了解如何渲染列表数据。