06Vue 3 列表渲染:概念与用法详解
一、核心概念
1.1 什么是列表渲染
列表渲染是将数组或对象的数据映射到 DOM 元素的过程,Vue 3 使用 v-for 指令来实现这一功能。
1.2 主要特性
-
基于数据源动态生成多个元素
-
自动响应数据变化
-
支持多种数据源类型
-
提供唯一 key 管理
二、基本用法
2.1 数组渲染
<template>
<!-- 基本用法 -->
<ul>
<li v-for="item in items" :key="item.id">
{{ item.name }}
</li>
</ul>
<!-- 获取索引 -->
<ul>
<li v-for="(item, index) in items" :key="item.id">
{{ index + 1 }}. {{ item.name }}
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, name: '项目一' },
{ id: 2, name: '项目二' },
{ id: 3, name: '项目三' }
])
</script>
2.2 对象渲染
<template>
<!-- 对象基本渲染 -->
<ul>
<li v-for="(value, key) in userInfo" :key="key">
{{ key }}: {{ value }}
</li>
</ul>
<!-- 带索引的对象渲染 -->
<ul>
<li v-for="(value, key, index) in userInfo" :key="key">
{{ index }}. {{ key }}: {{ value }}
</li>
</ul>
</template>
<script setup>
import { ref } from 'vue'
const userInfo = ref({
name: '张三',
age: 25,
email: '[email protected]'
})
</script>
2.3 使用数字范围
<template>
<!-- 渲染 1-10 -->
<div>
<span v-for="n in 10" :key="n">
{{ n }}
</span>
</div>
<!-- 渲染指定范围 -->
<div>
<span v-for="n in [5, 10, 15, 20]" :key="n">
{{ n }}
</span>
</div>
</template>
三、关键属性 :key 的重要性
3.1 为什么需要 key
<template>
<!-- 正确使用 key -->
<div>
<div
v-for="item in items"
:key="item.id" <!-- 推荐使用唯一标识 -->
class="item"
>
{{ item.content }}
</div>
</div>
<!-- 不推荐的做法 -->
<div>
<div
v-for="(item, index) in items"
:key="index" <!-- 仅在列表稳定时使用 -->
class="item"
>
{{ item.content }}
</div>
</div>
</template>
<script setup>
const items = ref([
{ id: 'unique-1', content: '内容一' },
{ id: 'unique-2', content: '内容二' }
])
</script>
3.2 key 的最佳实践
-
使用唯一标识符(如数据库 ID)
-
避免使用数组索引(除非列表从不重新排序)
-
key 值应该是字符串或数字
四、高级用法
4.1 与 v-if 结合使用
<template> <!-- 不推荐:v-for 和 v-if 在同一元素上 --> <div> <!-- 这种写法性能较差 --> <div v-for="item in items" v-if="item.isActive" :key="item.id"> {{ item.name }} </div> </div> <!-- 推荐:使用计算属性或 template 包裹 --> <div> <template v-for="item in items" :key="item.id"> <div v-if="item.isActive"> {{ item.name }} </div> </template> </div> </template> <script setup> import { computed } from 'vue' // 更好的方式:使用计算属性 const activeItems = computed(() => { return items.value.filter(item => item.isActive) }) </script>
4.2 在组件上使用 v-for
<template> <!-- 自定义组件列表 --> <ProjectItem v-for="project in projects" :key="project.id" :project="project" @select="handleSelect" /> </template> <script setup> import ProjectItem from './ProjectItem.vue' const projects = ref([ { id: 1, title: '项目A' }, { id: 2, title: '项目B' } ]) const handleSelect = (project) => { console.log('选中项目:', project) } </script>
4.3 嵌套循环
<template> <div v-for="category in categories" :key="category.id"> <h3>{{ category.name }}</h3> <ul> <li v-for="product in category.products" :key="product.id" > {{ product.name }} </li> </ul> </div> </template> <script setup> const categories = ref([ { id: 1, name: '电子产品', products: [ { id: 101, name: '手机' }, { id: 102, name: '电脑' } ] }, { id: 2, name: '书籍', products: [ { id: 201, name: 'Vue 3 指南' }, { id: 202, name: 'JavaScript 高级编程' } ] } ]) </script>
五、性能优化
5.1 使用计算属性减少渲染
<script setup> import { computed, ref } from 'vue' const rawItems = ref([ { id: 1, name: 'Item 1', active: true }, { id: 2, name: 'Item 2', active: false }, { id: 3, name: 'Item 3', active: true } ]) // 使用计算属性过滤和排序 const displayItems = computed(() => { return rawItems.value .filter(item => item.active) .sort((a, b) => a.name.localeCompare(b.name)) }) </script>
5.2 虚拟滚动(大数据量)
<template> <!-- 使用第三方库如 vue-virtual-scroller --> <RecycleScroller class="scroller" :items="largeList" :item-size="50" key-field="id" > <template #default="{ item }"> <div class="item"> {{ item.name }} </div> </template> </RecycleScroller> </template> <script setup> import { ref } from 'vue' const largeList = ref( Array.from({ length: 10000 }, (_, i) => ({ id: i + 1, name: `项目 ${i + 1}` })) ) </script> <style scoped> .scroller { height: 400px; } .item { height: 50px; line-height: 50px; border-bottom: 1px solid #eee; } </style>
六、响应式更新
6.1 数组更新检测
<script setup> import { ref } from 'vue' const items = ref(['A', 'B', 'C']) // 这些方法会触发视图更新 const updateArray = () => { // 变异方法(自动触发更新) items.value.push('D') // 添加 items.value.pop() // 移除最后一个 items.value.shift() // 移除第一个 items.value.unshift('Z') // 添加到开头 items.value.splice(1, 1) // 删除/替换 items.value.sort() // 排序 items.value.reverse() // 反转 // 非变异方法(需要重新赋值) items.value = items.value.filter(item => item !== 'B') items.value = items.value.concat(['E', 'F']) items.value = [...items.value, 'G'] } </script>
6.2 对象更新检测
<script setup> import { reactive } from 'vue' const user = reactive({ name: '张三', age: 25 }) // 添加新属性(需要特殊处理) const addProperty = () => { // 方法1:使用 Vue.set(Vue 2 风格) // import { set } from 'vue' // set(user, 'email', '[email protected]') // 方法2:直接赋值(推荐) user.email = '[email protected]' // 方法3:使用 Object.assign Object.assign(user, { address: '北京' }) } </script>
七、实际应用示例
7.1 待办事项列表
<template>
<div class="todo-app">
<input
v-model="newTodo"
@keyup.enter="addTodo"
placeholder="添加新任务"
/>
<ul>
<li
v-for="(todo, index) in todos"
:key="todo.id"
:class="{ completed: todo.completed }"
>
<input
type="checkbox"
v-model="todo.completed"
/>
<span>{{ todo.text }}</span>
<button @click="removeTodo(index)">删除</button>
</li>
</ul>
<div>总计: {{ totalTodos }}, 完成: {{ completedTodos }}</div>
</div>
</template>
<script setup>
import { ref, computed } from 'vue'
const newTodo = ref('')
const todos = ref([])
let idCounter = 1
const addTodo = () => {
if (newTodo.value.trim()) {
todos.value.push({
id: idCounter++,
text: newTodo.value,
completed: false
})
newTodo.value = ''
}
}
const removeTodo = (index) => {
todos.value.splice(index, 1)
}
const totalTodos = computed(() => todos.value.length)
const completedTodos = computed(() =>
todos.value.filter(todo => todo.completed).length
)
</script>
<style scoped>
.todo-app {
max-width: 400px;
margin: 0 auto;
}
.completed {
text-decoration: line-through;
color: #999;
}
li {
display: flex;
align-items: center;
gap: 10px;
margin: 5px 0;
}
</style>
八、注意事项
-
避免同时使用 v-for 和 v-if:优先使用计算属性过滤数据
-
始终提供唯一的 key:提高性能,避免渲染问题
-
避免直接修改数组长度:使用 splice 代替
-
大数据量使用虚拟滚动:提升渲染性能
-
复杂数据结构考虑组件化:提高可维护性
总结
Vue 3 的列表渲染功能强大而灵活,通过 v-for 指令可以轻松处理各种数据结构的渲染需求。合理使用 key、结合计算属性优化性能、遵循最佳实践,可以构建出高效且易维护的列表界面。
记住核心原则:让数据驱动视图,Vue 会自动处理数据变化到视图更新的过程。

浙公网安备 33010602011771号