优化 v-if 和 v-for 的性能是 Vue 开发中的常见问题,核心原则是:避免在同一元素上同时使用 v-if 和 v-for ,并采用更高效的数据处理和渲染策略。以下是具体优化方法,适用于 Vue 2 和 Vue 3(会标注差异):
1. 用计算属性(computed)预过滤数据
这是最推荐的方式,尤其适用于"根据条件筛选列表项"的场景。
低效写法(不要这样):
vue
<li v-for="user in users" v-if="user.isActive" :key="user.id">
{{ user.name }}
</li>
优化写法:
vue
<template>
<li v-for="user in activeUsers" :key="user.id">
{{ user.name }}
</li>
</template>
<script>
export default {
computed: {
activeUsers() {
// 只在 users 或相关依赖变化时重新计算
return this.users.filter(user => user.isActive);
}
}
}
</script>
优势:
- 过滤逻辑只在依赖变化时执行(缓存结果)
- 渲染层只需遍历最终结果,减少 DOM 操作
2. 将 v-if 移到外层容器
适用于"根据某个开关决定是否渲染整个列表"的场景。
vue
<template>
<!-- 先判断是否需要渲染列表 -->
<ul v-if="showList">
<li v-for="item in list" :key="item.id">
{{ item.name }}
</li>
</ul>
</template>
优势:
- 如果
showList === false,完全跳过v-for,节省遍历开销- 避免无谓的循环和条件判断
3. 使用虚拟滚动(长列表优化)
如果列表非常长(如 >1000 项),即使过滤后仍可能卡顿,此时应使用 虚拟滚动 技术(只渲染可视区域内的元素)。
常用库:
vue-virtual-scroller(Vue 2/3)vue3-virtual-scroller(Vue 3)
示例(简化):
vue
<RecycleScroller
class="scroller"
:items="activeUsers"
:item-size="54"
key-field="id"
v-slot="{ item }"
>
<div>{{ item.name }}</div>
</RecycleScroller>
4. 确保 :key 唯一且稳定
错误的 key 会导致不必要的 DOM 重建。
正确:
vue
<li v-for="item in list" :key="item.id">...</li>
错误:
vue
<li v-for="(item, index) in list" :key="index">...</li> <!-- 列表变动时 key 不稳定 -->
5. 避免在模板中调用方法(尤其是 v-for 内)
模板中的方法会在每次渲染时调用,无法缓存。
不推荐:
vue
<li v-for="item in list" :key="item.id">
{{ formatName(item) }} <!-- 每次都调用! -->
</li>
推荐:
- 使用 计算属性 预处理数据
- 或在
data中预先格式化好
6. Vue 3 特有优化:使用 <template> 分离逻辑
虽然 Vue 3 改变了 v-if/v-for 优先级,但仍建议分离:
vue
<template v-for="item in list" :key="item.id">
<li v-if="item.visible">{{ item.name }}</li>
</template>
注意:这种方式每个 item 仍会创建一个
<template>节点,仅适用于简单场景。首选仍是 computed 过滤。
性能对比总结
| 方案 | 是否推荐 | 适用场景 |
|---|---|---|
v-for + v-if 同元素 |
❌ 禁止 | --- |
computed 过滤 + v-for |
✅ 强烈推荐 | 条件筛选列表项 |
外层 v-if + 内层 v-for |
✅ 推荐 | 控制整个列表显示/隐藏 |
| 虚拟滚动 | ✅ 长列表必备 | 列表 > 100 项 |
合理使用 :key |
✅ 必须 | 所有 v-for |
官方建议
- Vue 2 文档:v-for with v-if
- Vue 3 文档:List Rendering > v-for with v-if