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

Featuresv-ifv-show
Rendering methodConditional rendering (real conditional rendering)Always render, only switch display
Switching overheadHigher (destroy and rebuild)Lower (only changes CSS)
Initial rendering overheadLower (no rendering when condition is false)Higher (always render)
Applicable scenariosConditions rarely changeFrequent 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 rebuilt
  • v-showJust toggle the CSS display property
  • v-ifSuitable for scenes where conditions rarely change
  • v-showSuitable for frequent switching scenarios
  • can be usedv-elseandv-else-ifCreate more complex conditional logic

Next step

Next, learn List Rendering to learn how to render list data.