目录
- [一、v-for 详解](#一、v-for 详解)
- [1.1 作用](#1.1 作用)
- [1.2 语法](#1.2 语法)
- [1.3 要点](#1.3 要点)
- [二、v-if 详解](#二、v-if 详解)
- [2.1 作用](#2.1 作用)
- [2.2 语法](#2.2 语法)
- [2.3 v-if vs v-show](#2.3 v-if vs v-show)
- [三、高频面试坑点:v-for 和 v-if 不能用在同一个标签上](#三、高频面试坑点:v-for 和 v-if 不能用在同一个标签上)
- [3.1 错误示例](#3.1 错误示例)
- [3.2 原因](#3.2 原因)
- [3.3 正确写法](#3.3 正确写法)
- [四、v-for 里面的 key 作用](#四、v-for 里面的 key 作用)
- [4.1 一句话核心答案](#4.1 一句话核心答案)
- [4.2 详细解释](#4.2 详细解释)
- [4.3 图解:有 key vs 无 key](#4.3 图解:有 key vs 无 key)
- [4.4 为什么不能用 index 做 key?(高频考点)](#4.4 为什么不能用 index 做 key?(高频考点))
- 五、面试标准满分回答
- [Q1:v-for 和 v-if 为什么不能一起用?](#Q1:v-for 和 v-if 为什么不能一起用?)
- [Q2:v-for 中的 key 有什么作用?为什么不能用 index?](#Q2:v-for 中的 key 有什么作用?为什么不能用 index?)
- 六、总结对比表
一、v-for 详解
1.1 作用
v-for 是循环指令,用于遍历数组或对象渲染列表,必须绑定 key 提升性能。
1.2 语法
javascript
<template>
<!-- 遍历数组 -->
<div v-for="(item, index) in list" :key="index">
{{ item }}
</div>
<!-- 遍历对象 -->
<div v-for="(value, key, index) in obj" :key="key">
{{ key }}: {{ value }}
</div>
<!-- 遍历数字(1-10) -->
<div v-for="n in 10" :key="n">{{ n }}</div>
<!-- 遍历字符串 -->
<div v-for="char in 'hello'" :key="char">{{ char }}</div>
</template>
1.3 要点
| 要点 | 说明 |
|---|---|
| 必须绑定 key | 提高 Vue 复用 DOM、diff 效率 |
| 可遍历类型 | 数组、对象、数字、字符串 |
| 参数顺序 | 数组:(item, index);对象:(value, key, index) |
二、v-if 详解
2.1 作用
v-if 是条件渲染指令,根据表达式真假创建或销毁 DOM。
2.2 语法
javascript
<template>
<!-- 单独使用 -->
<div v-if="isShow">显示</div>
<!-- v-else -->
<div v-if="isLogin">欢迎回来</div>
<div v-else>请先登录</div>
<!-- v-else-if -->
<div v-if="status === 'success'">成功</div>
<div v-else-if="status === 'loading'">加载中</div>
<div v-else>失败</div>
<!-- 支持 template 批量渲染 -->
<template v-if="isShow">
<h2>标题</h2>
<p>内容</p>
</template>
</template>
2.3 v-if vs v-show
| 对比 | v-if | v-show |
|---|---|---|
| 控制方式 | 创建/销毁 DOM | 切换 display: none |
| DOM 存在性 | 假时不存在 | 始终存在 |
| 切换开销 | 高 | 低 |
| 初始开销 | 低(假时不渲染) | 高(总是渲染) |
| 支持 template | ✅ | ❌ |
| 支持 v-else | ✅ | ❌ |
| 适用场景 | 很少切换 | 频繁切换 |
三、高频面试坑点:v-for 和 v-if 不能用在同一个标签上
3.1 错误示例
javascript
<!-- ❌ 不推荐!!! -->
<div v-for="item in list" v-if="item.isActive" :key="item.id">
{{ item.name }}
</div>
3.2 原因
v-for 优先级比 v-if 高,会先循环全部项,再逐个判断 v-if,造成性能浪费:
javascript
// 本质执行逻辑(简化)
// 即使只有 1 项符合条件,也要遍历全部 1000 条数据
list.forEach(item => {
if (item.isActive) {
// 渲染 DOM
}
})
3.3 正确写法
javascript
<!-- ✅ 方式1:在外层套 <template> -->
<template v-for="item in list" :key="item.id">
<div v-if="item.isActive">
{{ item.name }}
</div>
</template>
<!-- ✅ 方式2:提前在 computed 里过滤好数组 -->
<template>
<div v-for="item in activeList" :key="item.id">
{{ item.name }}
</div>
</template>
<script setup>
import { computed } from 'vue'
const list = ref([...])
const activeList = computed(() =>
list.value.filter(item => item.isActive)
)
</script>
<!-- ✅ 方式3:v-show 替代(如果只是隐藏) -->
<div v-for="item in list" v-show="item.isActive" :key="item.id">
{{ item.name }}
</div>
四、v-for 里面的 key 作用
4.1 一句话核心答案
key 是 Vue 用来识别每个虚拟 DOM 节点的唯一标识,方便 Vue 在列表更新时做高效的 DIFF 对比,实现 DOM 复用和精准更新,提升渲染性能。
4.2 详细解释
| 作用 | 说明 |
|---|---|
| 标识唯一性 | key 给每个列表项一个唯一 ID,让 Vue 知道谁是谁 |
| 提高 diff 效率 | 有 key:Vue 能精准找到变化项,只更新该 DOM;无 key:Vue 只能暴力复用、顺序对比 |
| 避免渲染错乱 | 删除、逆序、插入时,没有 key 容易出现复选框错位、过渡动画混乱 |
4.3 图解:有 key vs 无 key
无 key(索引对比):
原列表:A B C D
新列表:A C D
Vue 对比:
位置0: A → A ✅ 复用
位置1: B → C ❌ 更新(但 B 应该是删除)
位置2: C → D ❌ 更新
位置3: D → 无 ❌ 删除
结果:2 次更新 + 1 次删除
有 key(id 对比):
原列表:A(id:1) B(id:2) C(id:3) D(id:4)
新列表:A(id:1) C(id:3) D(id:4)
Vue 对比:
id:1 存在 ✅ 复用
id:2 不存在 ❌ 删除
id:3 存在 ✅ 复用
id:4 存在 ✅ 复用
结果:1 次删除,0 次更新
4.4 为什么不能用 index 做 key?(高频考点)
javascript
<!-- ❌ 错误:用 index 做 key -->
<div v-for="(item, index) in list" :key="index">
{{ item.name }}
<input type="checkbox" />
</div>
问题:
| 操作 | 用 index 作为 key 的问题 |
|---|---|
| 列表逆序 | index 变化,所有 key 都变了,Vue 会重新创建所有 DOM |
| 删除/插入 | 后续项的 index 改变,导致 DOM 复用错误 |
| 表单错位 | input 框的内容会错位,因为 key 变了 |
| 性能 | 大量不必要的 DOM 更新,性能反而更差 |
正确做法:
javascript
<!-- ✅ 正确:用后端返回的唯一 id -->
<div v-for="item in list" :key="item.id">
{{ item.name }}
</div>
<!-- ✅ 数据没有 id 时,可以用 Symbol 或自定义唯一标识 -->
<div v-for="(item, index) in list" :key="`item-${item.name}-${item.age}`">
{{ item.name }}
</div>
五、面试标准满分回答
Q1:v-for 和 v-if 为什么不能一起用?
答: 因为 v-for 的优先级高于 v-if,如果写在同一个标签上,Vue 会先执行循环遍历所有数据,再对每一项进行条件判断。这样即使大部分数据都不需要渲染,也会先遍历一遍,造成性能浪费。正确的做法是用 computed 先过滤数据,或者在
<template>外层包一层。
Q2:v-for 中的 key 有什么作用?为什么不能用 index?
答: key 是 Vue 虚拟 DOM diff 算法中识别节点的唯一标识。有 key 时,Vue 能精准定位变化项,只更新必要的 DOM;没有 key 时,Vue 只能按顺序对比,容易造成错误渲染和性能问题。
不能用 index 作为 key,因为当列表发生逆序、删除、插入等操作时,index 会变化,导致 Vue 认为所有节点都变了,从而无法复用 DOM,反而降低性能,还可能导致表单状态错位。应该使用后端返回的唯一 id 作为 key。
六、总结对比表
| 指令 | 作用 | 优先级 | 必须配合 | 注意事项 |
|---|---|---|---|---|
| v-for | 循环渲染 | 高 | :key | 不要和 v-if 同标签 |
| v-if | 条件渲染 | 中 | v-else-if/v-else | 切换开销大 |
| key | 节点标识 | - | 配合 v-for | 不要用 index |