列表渲染
在 Vue 中,列表渲染是通过 v-for 指令实现的,它允许你遍历数组或对象,将数据渲染成一组 DOM 元素或组件。
🧱 基本语法
<div v-for="item in items" :key="item.id">
{{ item.text }}
</div>
等价形式:
v-for="(item, index) in items"
📦 作用对象
遍历数组:
<ul>
<li v-for="(fruit, index) in fruits" :key="index">
{{ index }} - {{ fruit }}
</li>
</ul>
data() {
return {
fruits: ['苹果', '香蕉', '橙子']
}
}
遍历对象:
<div v-for="(value, key, index) in user" :key="key">
{{ index }}. {{ key }}: {{ value }}
</div>
data() {
return {
user: {
name: 'Tom',
age: 25,
email: 'tom@example.com'
}
}
}
遍历数字范围:
<span v-for="n in 5" :key="n">{{ n }}</span>
输出:1 2 3 4 5
🧩 与组件配合渲染
<user-card
v-for="user in users"
:key="user.id"
:user="user"
/>
🔁 使用 包裹多个元素
当 v-for 要渲染多个根节点时,应使用 :
<template v-for="item in items" :key="item.id">
<h3>{{ item.title }}</h3>
<p>{{ item.content }}</p>
</template>
⚠️ 注意事项
不要同时在同一个元素上使用 v-for 和 v-if,因为二者优先级不同,容易出 bug。
- 错误写法:
<li v-for="item in items" v-if="item.show">...</li>
- 正确做法:用 包裹
<template v-for="item in items" :key="item.id">
<li v-if="item.show">...</li>
</template>
异步数据加载前 v-for 列表为空时,注意防空判断或 loading 状态。
列表变更会影响性能,使用 track-by(Vue 3 使用 :key)优化 diff。
✅ 总结
用法 | 语法示例 |
---|---|
遍历数组 | v-for=“item in list” |
遍历数组含索引 | v-for=“(item, i) in list” |
遍历对象 | v-for=“(value, key, index) in obj” |
遍历数字范围 | v-for=“n in 10” |
多元素渲染 | … |
搭配组件 |
🧠 本质是什么?
在 Vue 中,v-for 是一个结构性指令,用于根据数据生成多个“重复的 DOM 结构或组件实例”。它的工作本质就是:
将一组数据映射成一组 VNode(虚拟 DOM 节点),并最终渲染为真实 DOM。
例如:
<li v-for="item in items" :key="item.id">
{{ item }}
</li>
Vue 会编译为一个 render 函数,大致等价于:
items.map(item => h('li', { key: item.id }, item))
⚙️ 编译 & 渲染机制
Vue 的编译器在遇到 v-for 时:
- 生成 for 的 AST 节点(抽象语法树)
- 转换为 JS 渲染函数(render 函数)
- 最终运行时将数据映射为 VNode 数组
虚拟 DOM 映射:
items = ['a', 'b', 'c']
→ VDOM:
[
VNode(li, 'a'),
VNode(li, 'b'),
VNode(li, 'c')
]
在更新时,Vue 会通过 key 进行diff 算法优化比较,避免不必要的 DOM 更新。
🧩 key 的作用 —— diff 的关键
在多次渲染中,Vue 依靠 key 判断每个 VNode 是否相同。
举例:
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
如果你用的是 :key=“index” 或无 key,Vue 会可能错误地复用 DOM 元素,导致状态错乱(尤其是 或 )。
✅ 正确使用唯一且稳定的 key 是性能和正确性的保障。
🔁 4动态更新的影响
增加 / 删除项
Vue 能自动追踪数组变更,比如 push、splice、pop 等,自动触发视图更新。
this.items.push({ id: 4, text: 'D' })
// 会更新 DOM
修改项
Vue 能追踪响应式对象属性的变化,但对 数组的下标修改 要特别注意(Vue 2):
this.items[0] = 'new' // ❌ Vue 2 无法检测(Vue 3 支持)
this.$set(this.items, 0, 'new') // ✅ Vue 2 中正确方式
👻 多层嵌套与作用域
你可以嵌套多个 v-for:
<div v-for="group in groups" :key="group.id">
<p>{{ group.name }}</p>
<ul>
<li v-for="user in group.users" :key="user.id">{{ user.name }}</li>
</ul>
</div>
每个 v-for 都会有自己的作用域,内部访问的是它那一层的数据。
💥 性能思维
性能风险场景:
- 渲染非常大的列表(如 10,000 条)→ 应使用 虚拟滚动(虚拟列表)
- 动态频繁变动的列表(如聊天流)→ 需优化 key、避免重复创建
- 使用不稳定 key(如 index)→ 导致 DOM 复用错误
🎭与 配合使用(带动画)
Vue 提供 组件支持列表过渡动画:
<transition-group name="fade" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item }}
</li>
</transition-group>
你可以为添加、删除、移动等动画做优化体验。
✅ 总结
v-for 列表渲染
├── 核心功能:数据 → 多个节点(VNode → DOM)
├── 编译机制:编译成 map 函数,生成 VNode 数组
├── key 的作用:辅助 diff 算法判断节点是否复用
├── 使用场景
│ ├── 遍历数组 / 对象
│ ├── 嵌套多层结构
│ └── 渲染组件
├── 性能注意
│ ├── 避免 index 做 key
│ ├── 大列表使用虚拟滚动
│ └── 频繁变更时减少渲染量
└── 进阶配合
├── 包裹多元素
├── 做动画
└── 动态增删 & 响应式更新