详细对比 v-for、v-if 和 v-show这三个指令的特性和使用场景。
指令 | 作用 | 生命周期 | 性能特点 | 使用场景 |
v-for | 循环渲染列表 | 列表项有完整生命周期 | 列表长度影响性能 | 动态列表、表格数据 |
v-if | 条件渲染 | 条件变化时销毁/重建 | 切换成本高 | 条件性显示、懒加载 |
v-show | 条件显示 | 只触发挂载,不销毁 | 切换成本低 | 频繁切换、标签页 |
<template>
<div>
<div v-for="(item, index) in items" :key="item.id">
{{ item.name }} - {{ index }}
</div>
</div>
</template>
<script setup>
const items = ref([
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' }
])
</script>特点:
<template>
<div>
<AdminPanel v-if="user.role === 'admin'" />
<UserPanel v-else-if="user.role === 'user'" />
<GuestPanel v-else />
</div>
</template>特点:
<template>
<div>
<TabContent v-show="activeTab === 'home'" />
<TabContent v-show="activeTab === 'profile'" />
</div>
</template>特点:
<template>
<!-- 不推荐:v-for 和 v-if 在同一元素 -->
<div v-for="item in items" v-if="item.isActive" :key="item.id">
{{ item.name }}
</div>
<!-- 推荐:使用 computed 过滤 -->
<div v-for="item in activeItems" :key="item.id">
{{ item.name }}
</div>
<!-- 或者使用 template -->
<template v-for="item in items" :key="item.id">
<div v-if="item.isActive">
{{ item.name }}
</div>
</template>
</template>
<script setup>
const activeItems = computed(() =>
items.value.filter(item => item.isActive)
)
</script><template>
<div>
<div
v-for="item in items"
:key="item.id"
v-show="item.isVisible"
>
{{ item.name }}
</div>
</div>
</template>场景 | 推荐方案 | 理由 |
动态列表 | v-for+ :key | 专门为列表设计 |
权限控制 | v-if | 条件性渲染,安全 |
标签页切换 | v-show | 平滑切换,保持状态 |
大数据列表 | v-for+ 虚拟滚动 | 性能优化 |
复杂组件懒加载 | v-if | 减少初始加载时间 |
频繁显示/隐藏 | v-show | 切换性能好 |
<template>
<!-- ✅ 推荐 -->
<template v-if="shouldRender">
<ComponentA />
<ComponentB />
</template>
<!-- ✅ 推荐:使用计算属性 -->
<div v-for="item in visibleItems" :key="item.id">
{{ item.name }}
</div>
<!-- ❌ 避免:在同一元素使用 v-for 和 v-if -->
<div v-for="item in items" v-if="item.visible" :key="item.id">
{{ item.name }}
</div>
<!-- ✅ 好的:使用 template 包裹 -->
<template v-for="item in items" :key="item.id">
<div v-if="item.visible">
{{ item.name }}
</div>
</template>
</template><script setup>
// 大型数据及时清理
onUnmounted(() => {
bigData.value = null // 协助 GC
})
// 使用 shallowRef 避免深度响应式
const largeList = shallowRef(bigArray)
// 分块处理大数据
const processInChunks = (data) => {
for (let i = 0; i < data.length; i += 1000) {
setTimeout(() => {
// 处理数据块
}, 0)
}
}
</script>根据具体场景选择合适的指令组合,才能达到最佳的开发体验和运行时性能。