#Vue.js conditional rendering
#v-if directive
v-ifDirectives are used to render elements conditionally. When the condition is true, the element will be rendered; when it is false, the element will not be rendered into the DOM.
#Basic usage
<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-elsemust follow closelyv-iforv-else-iflater:
<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
<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>#Use v-if on template
When you need to switch multiple elements, you can<template>Use onv-if:
<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 command
v-showAlso used to conditionally display an element, but it just toggles the CSS of the elementdisplayproperty.
<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
#the difference
| Features | v-if | v-show |
|---|---|---|
| Rendering method | Conditional rendering (real conditional rendering) | Always render, only switch display |
| Switching overhead | Higher (destroy and rebuild) | Lower (only changes CSS) |
| Initial rendering overhead | Lower (no rendering when condition is false) | Higher (always render) |
| Applicable scenarios | Conditions rarely change | Frequent switching |
#Select suggestions
<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>#Practical example: user login status
<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>#Practical example: loading status
<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>#Practical example: permission control
<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>#Summarize
v-ifIs true conditional rendering, elements will be destroyed and rebuiltv-showJust toggle the CSS display propertyv-ifSuitable for scenes where conditions rarely changev-showSuitable for frequent switching scenarios- can be used
v-elseandv-else-ifCreate more complex conditional logic
#Next step
Next, learn List Rendering to learn how to render list data.