👽第5节:列表渲染与 key 的作用
—— 动态渲染集合数据,掌握 {#each}
语法与 key
的核心价值
👋 引言:构建动态内容的核心能力
在前几节课中,我们学习了 Svelte 中的数据绑定、响应式变量、事件处理等基础能力。本节老曹将重点讲解 如何在 Svelte 中高效地渲染动态列表,并深入理解 key
在列表更新时的作用。
列表渲染是现代前端开发中最常见的需求之一,无论是展示商品列表、用户评论、消息通知等,都离不开对数组的循环遍历和动态更新。
我们将从基本的 {#each}
语法讲起,逐步介绍嵌套列表、索引使用、条件判断、key
的作用与最佳实践,并通过实战练习打造一个可交互的待办事项列表组件(To-Do List)。
📚 课程目标
- 掌握 Svelte 中
{#each}
列表渲染的基本语法 - 理解
index
和key
的作用与使用场景 - 学会在列表中嵌套逻辑(如条件判断)
- 实现动态添加/删除/标记完成等功能
- 构建一个完整的 To-Do List 组件作为课堂实战
🧱 一、基本列表渲染 {#each}
1. 基础用法
Svelte 使用 {#each array as item}
来循环渲染列表:
<script>
let items = ['苹果', '香蕉', '橘子'];
</script>
<ul>
{#each items as fruit}
<li>{fruit}</li>
{/each}
</ul>
2. 获取索引值(index)
可以使用 as (item, index)
获取当前项和索引:
{#each items as fruit, i}
<li>第 {i + 1} 个水果:{fruit}</li>
{/each}
🔁 二、动态更新列表数据
1. 添加新项
<script>
let items = ['苹果', '香蕉'];
let newItem = '';
function addItem() {
if (newItem.trim()) {
items = [...items, newItem];
newItem = '';
}
}
</script>
<input type="text" bind:value={newItem}>
<button on:click={addItem}>添加</button>
<ul>
{#each items as fruit}
<li>{fruit}</li>
{/each}
</ul>
2. 删除某一项(根据索引或值)
function removeItem(index) {
items = items.filter((_, i) => i !== index);
}
在模板中调用:
{#each items as fruit, i}
<li>
{fruit}
<button on:click={() => removeItem(i)}>删除</button>
</li>
{/each}
🧠 三、key 的作用与优化机制
1. 为什么需要 key
?
当列表数据发生变化时,Svelte 默认基于“位置”来更新 DOM 节点。这可能导致一些问题,比如:
- 表单输入框中的内容错位;
- 动画状态丢失;
- 渲染效率低下。
使用 key
可以告诉 Svelte 每个节点的唯一标识,确保它正确识别哪些元素发生了变化。
2. 正确使用 key
{#each items as item (item.id)}
<div>{item.name}</div>
{/each}
括号内的 (item.id)
就是 key
,它可以是任意表达式,只要能唯一标识该项即可。
✅ 推荐使用唯一 ID 作为 key
例如:
<script>
let todos = [
{ id: 1, text: '买菜' },
{ id: 2, text: '洗衣服' },
{ id: 3, text: '写代码' }
];
</script>
{#each todos as todo (todo.id)}
<div>{todo.text}</div>
{/each}
🧩 四、嵌套逻辑与条件渲染
可以在 {#each}
内部嵌套其他控制语句,如 {#if}
:
<script>
let todos = [
{ id: 1, text: '买菜', done: true },
{ id: 2, text: '洗衣服', done: false },
{ id: 3, text: '写代码', done: false }
];
</script>
<ul>
{#each todos as todo (todo.id)}
<li class:completed={todo.done}>
<input type="checkbox" bind:checked={todo.done}>
{todo.text}
</li>
{/each}
</ul>
<style>
.completed {
text-decoration: line-through;
color: gray;
}
</style>
💡 五、课堂实战练习
🎯 实战任务:构建一个功能完备的 To-Do List 应用
功能要求:
- 显示所有待办事项;
- 支持添加新待办;
- 支持删除指定待办;
- 支持勾选已完成状态;
- 已完成事项带删除线样式;
- 使用
key
提升渲染性能;
示例代码:
TodoList.svelte
<script>
let todos = [
{ id: 1, text: '学习 Svelte', done: false },
{ id: 2, text: '复习 Git Flow', done: true }
];
let newTodo = '';
function addTodo() {
if (newTodo.trim()) {
todos = [
...todos,
{ id: Date.now(), text: newTodo, done: false }
];
newTodo = '';
}
}
function toggleDone(id) {
todos = todos.map(todo =>
todo.id === id ? { ...todo, done: !todo.done } : todo
);
}
function removeTodo(id) {
todos = todos.filter(todo => todo.id !== id);
}
</script>
<h2>我的待办事项</h2>
<div>
<input type="text" bind:value={newTodo} placeholder="新增待办">
<button on:click={addTodo}>添加</button>
</div>
<ul>
{#each todos as todo (todo.id)}
<li class:done={todo.done}>
<label>
<input type="checkbox" checked={todo.done} on:change={() => toggleDone(todo.id)}>
{todo.text}
</label>
<button on:click={() => removeTodo(todo.id)}>删除</button>
</li>
{/each}
</ul>
<style>
.done {
text-decoration: line-through;
color: #888;
}
ul {
list-style: none;
padding: 0;
}
li {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
</style>
📝 六、总结
本节课我们系统掌握了:
- Svelte 中使用
{#each}
进行列表渲染的基本语法 - 如何获取索引值
index
并用于操作列表项 - 动态添加、删除、更新列表数据的方法
key
的作用及其在列表更新中的重要性- 实战构建了一个支持交互的 To-Do List 待办事项组件
这些知识是构建复杂数据驱动型应用的关键技能。下一讲我们将进入表单与验证的学习,进一步提升对用户输入控制的能力。
📘 附录资源推荐
- Svelte 官方文档 -
{#each}
- React/Vue/Svelte 列表渲染对比指南
- VSCode 插件推荐:
Svelte for VS Code
Prettier
+ESLint
配合格式化与规范检查
🎯 课后作业
- 修改 To-Do List 组件,使其支持“全部完成”按钮。
- 实现一个“筛选器”按钮组,显示“全部”、“已完成”、“未完成”三种视图。
- 尝试为每个待办事项添加“编辑”功能,点击文字后变为输入框进行修改。
🤖 10大高频面试题(含答案)
✅ Q1: 在 Svelte 中如何渲染一个列表?
答:
使用 {#each array as item}
结构渲染列表:
{#each items as item}
<div>{item}</div>
{/each}
✅ Q2: 如何在 {#each}
中获取当前索引?
答:
使用 (item, index)
形式获取索引:
{#each items as item, i}
<div>第 {i + 1} 项:{item}</div>
{/each}
✅ Q3: 什么是 key
?为什么在列表中要使用它?
答:
key
是用来帮助 Svelte 高效更新 DOM 的标识符。不使用 key
时,Svelte 会基于“位置”来更新节点,可能导致动画错乱、表单数据混乱等问题。
{#each items as item (item.id)}
<div>{item.name}</div>
{/each}
✅ Q4: key
的最佳实践是什么?
答:
- 使用唯一 ID 作为
key
; - 不建议使用索引(除非数据顺序固定);
- 避免使用随机数(会导致每次重新创建元素);
✅ Q5: 如何实现动态添加/删除列表项?
答:
- 添加:使用展开运算符更新数组;
- 删除:使用
filter
方法过滤掉对应项;
items = [...items, newItem];
items = items.filter((_, i) => i !== index);
✅ Q6: Svelte 中是否支持嵌套 {#each}
?
答:
是的,支持多层嵌套:
{#each categories as category}
<h3>{category.name}</h3>
<ul>
{#each category.items as item}
<li>{item}</li>
{/each}
</ul>
{/each}
✅ Q7: 如何在列表项中使用条件渲染?
答:
在 {#each}
内部嵌套 {#if}
即可:
{#each items as item}
{#if item.active}
<li>{item.name}</li>
{/if}
{/each}
✅ Q8: 列表项中使用 bind:checked
是否会影响渲染性能?
答:
不会。Svelte 的响应式系统非常高效,直接使用 bind:checked
是推荐做法。
✅ Q9: 列表项的 key
可否使用索引?
答:
可以,但不推荐。因为当列表顺序变化时,索引可能重复使用,导致组件状态错乱。建议使用唯一 ID。
✅ Q10: Svelte 的列表渲染机制与其他框架有何不同?
答:
- React/Vue 使用虚拟 DOM diffing 算法比较差异;
- Svelte 在编译阶段生成高效的更新代码,无需运行时 diff;
- Svelte 的
{#each}
更加直观、简洁、性能更优;
🎯 总结:
这些问题覆盖了 Svelte 的列表渲染语法、key
的作用、动态更新、嵌套结构、性能优化等核心知识点,适合大家用于初级到中级前端岗位的面试准备。掌握这些内容将帮助你构建出高效、稳定的数据展示组件,并为进一步学习表单验证、生命周期钩子等进阶技能打下良好基础。