【Svelte】第五节:列表渲染与 key 的作用

👽第5节:列表渲染与 key 的作用

—— 动态渲染集合数据,掌握 {#each} 语法与 key 的核心价值


👋 引言:构建动态内容的核心能力

在前几节课中,我们学习了 Svelte 中的数据绑定、响应式变量、事件处理等基础能力。本节老曹将重点讲解 如何在 Svelte 中高效地渲染动态列表,并深入理解 key 在列表更新时的作用。

列表渲染是现代前端开发中最常见的需求之一,无论是展示商品列表、用户评论、消息通知等,都离不开对数组的循环遍历和动态更新。

我们将从基本的 {#each} 语法讲起,逐步介绍嵌套列表、索引使用、条件判断、key 的作用与最佳实践,并通过实战练习打造一个可交互的待办事项列表组件(To-Do List)。


📚 课程目标

  • 掌握 Svelte 中 {#each} 列表渲染的基本语法
  • 理解 indexkey 的作用与使用场景
  • 学会在列表中嵌套逻辑(如条件判断)
  • 实现动态添加/删除/标记完成等功能
  • 构建一个完整的 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 待办事项组件

这些知识是构建复杂数据驱动型应用的关键技能。下一讲我们将进入表单与验证的学习,进一步提升对用户输入控制的能力。


📘 附录资源推荐


🎯 课后作业

  1. 修改 To-Do List 组件,使其支持“全部完成”按钮。
  2. 实现一个“筛选器”按钮组,显示“全部”、“已完成”、“未完成”三种视图。
  3. 尝试为每个待办事项添加“编辑”功能,点击文字后变为输入框进行修改。

🤖 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 的作用、动态更新、嵌套结构、性能优化等核心知识点,适合大家用于初级到中级前端岗位的面试准备。掌握这些内容将帮助你构建出高效、稳定的数据展示组件,并为进一步学习表单验证、生命周期钩子等进阶技能打下良好基础。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全栈前端老曹

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值