diff --git a/files/zh-cn/learn/tools_and_testing/client-side_javascript_frameworks/svelte_components/index.md b/files/zh-cn/learn/tools_and_testing/client-side_javascript_frameworks/svelte_components/index.md new file mode 100644 index 00000000000000..dd618705471dde --- /dev/null +++ b/files/zh-cn/learn/tools_and_testing/client-side_javascript_frameworks/svelte_components/index.md @@ -0,0 +1,562 @@ +--- +title: 将我们的 Svelte 应用组件化 +slug: Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_components +l10n: + sourceCommit: e9be22eaa7416206e3f263a058f0d509a7f81f88 +--- + +{{LearnSidebar}} +{{PreviousMenuNext("Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_variables_props","Learn/Tools_and_testing/Client-side_JavaScript_frameworks/Svelte_reactivity_lifecycle_accessibility", "Learn/Tools_and_testing/Client-side_JavaScript_frameworks")}} + +在上一篇文章中,我们开始开发我们的待办事项列表应用。本文的主要目标是讲解如何将我们的应用拆分为可管理的组件,并在它们之间共享信息。我们将对应用进行组件化,并添加更多功能,以允许用户更新现有组件。 + + + + + + + + + + + + +
前提: +

+ 至少,建议你熟悉核心的 + HTMLCSS 和 + JavaScript + 语言,并了解终端/命令行的知识。 +

+

+ 你需要安装了 Node.js 和 npm 的终端来编译和构建应用。 +

+
目标: + 学习如何将我们的应用拆分为组件并在它们之间共享信息。 +
+ +## 跟随我们一起编码 + +### Git + +克隆 GitHub 仓库(如果尚未完成): + +```bash +git clone https://github.com/opensas/mdn-svelte-tutorial.git +``` + +然后进入当前应用程序状态: + +```bash +cd mdn-svelte-tutorial/04-componentizing-our-app +``` + +或者直接下载文件夹的内容: + +```bash +npx degit opensas/mdn-svelte-tutorial/04-componentizing-our-app +``` + +记得运行 `npm install && npm run dev` 以在开发模式下启动应用程序。 + +### REPL + +要使用 REPL 跟随我们一起编码,请从以下链接开始: + + + +## 将应用拆分为组件 + +在 Svelte 中,应用程序由一个或多个组件组成。组件是可重用的、自包含的代码块,将 HTML、CSS 和 JavaScript 组合在一起,写入 `.svelte` 文件中。组件可大可小,但通常具有明确定义:最有效的组件只服务于某个明确的目的。 + +定义组件的好处类似于将代码组织成可管理的片段的更一般的最佳实践。它将帮助你理解它们之间的关系,促进重用,并使你的代码更易于理解、维护和扩展。 + +但是,你如何知道什么应该拆分为组件呢? + +这没有硬性规定。有些人更喜欢直观的方法,开始查看标记并在每个似乎具有自己逻辑的组件和子组件周围绘制封装。 + +其他人借鉴了一些用于创建新函数或对象的技术。其中一种技术是单一职责原则——也就是说,一个组件理想情况下只做一件事。如果它变得越来越庞大,应该将其拆分为更小的子组件。 + +这两种方法应相互补充,并帮助你决定如何更好地组织你的组件。 + +最终,我们将应用拆分为以下组件: + +- `Alert.svelte`:用于通知已发生的操作的通用通知框。 +- `NewTodo.svelte`:允许你输入新的待办事项的文本输入框和按钮。 +- `FilterButton.svelte`:允许你对显示的待办事项应用过滤器的 _All_、_Active_ 和 _Completed_ 按钮。 +- `TodosStatus.svelte`:显示“x out of y items completed”(已完成 x 个项目中的 y 个)标题。 +- `Todo.svelte`:单个待办事项。每个可见的待办事项将在此组件的独立副本中显示。 +- `MoreActions.svelte`:允许你在界面底部对待办事项执行批量操作的 _Check All_(全选)和 _Remove Completed_(删除已完成)按钮。 + +![我们应用程序中组件的图形表示](01-todo-components.png) + +在本文中,我们将专注于创建 `FilterButton` 和 `Todo` 组件;我们将在以后的文章中介绍其他组件。 + +让我们开始吧。 + +> **备注:** 在创建我们的前几个组件的过程中,我们还将学习不同的组件间通信技术以及每种技术的优缺点。 + +## 提取我们的过滤器组件 + +我们将首先创建 `FilterButton.svelte` 组件。 + +1. 首先,创建一个新文件 `components/FilterButton.svelte`。 +2. 在这个文件中,我们将声明 `filter` 属性,并从 `Todos.svelte` 中复制相关的标记。将以下内容添加到文件中: + + ```svelte + + +
+ + + +
+ ``` + +3. 回到我们的 `Todos.svelte` 组件,我们想要使用我们的 `FilterButton` 组件。首先,我们需要导入它。在 `Todos.svelte` 的 ` + ``` + +3. 再次尝试你的应用程序,你应该仍然可以看到你的过滤器正常工作。 + +## 创建我们的 Todo 组件 + +现在,我们将创建一个 `Todo` 组件,用于封装每个单独的待办事项,包括复选框和一些编辑逻辑,以便你可以更改现有的待办事项。 + +我们的 `Todo` 组件将接收一个 `todo` 对象作为属性。让我们声明 `todo` 属性并将代码从 `Todos` 组件中移动到其中。暂时,我们将删除对 `removeTodo` 的调用,并替换为一个提示框。稍后我们将重新添加该功能。 + +1. 创建一个新的组件文件 `components/Todo.svelte`。 +2. 将以下内容放入该文件中: + + ```svelte + + +
+
+ todo.completed = !todo.completed} + checked={todo.completed} + /> + +
+
+ + +
+
+ ``` + +3. 现在,我们需要将 `Todo` 组件导入到 `Todos.svelte` 中。现在转到该文件,并在之前的导入语句下面添加以下 `import` 语句: + + ```js + import Todo from "./Todo.svelte"; + ``` + +4. 接下来,我们需要更新 `{#each}` 块,以包含每个待办事项的 `` 组件,而不是移动到 `Todo.svelte` 的代码。我们还将当前的 `todo` 对象作为一个属性传递给组件。 + + 将 `Todos.svelte` 中的 `{#each}` 块更新如下: + + ```svelte + + ``` + + 待办事项列表将显示在页面上,复选框应该可以正常工作(尝试勾选/取消勾选几个,然后观察过滤器是否按预期工作),但是我们的“x out of y items completed”状态标题将不再相应地更新。这是因为我们的 `Todo` 组件通过属性接收待办事项,但没有向其父组件发送任何信息。我们将在以后修复这个问题。 + +## 在组件之间共享数据:属性向下传递、事件向上传播模式 + +`bind` 指令非常简单直观,可以让你在父组件和子组件之间共享数据。然而,当应用程序变得更大、更复杂时,便难以跟踪所有绑定的值。另一种方法是使用“属性向下传递、事件向上传播”通信模式。 + +基本上,该模式依赖于子组件通过属性从父组件接收数据,而父组件通过处理子组件发出的事件来更新其状态。因此,从父组件向子组件*流动*属性,从子组件向父组件*冒泡*事件。这种模式建立了一种可预测且更易于理解的信息双向流动方式。 + +让我们看看如何使用自定义事件重新实现缺失的*删除*按钮功能。 + +为了创建自定义事件,我们将使用 `createEventDispatcher` 程序。它将返回一个 `dispatch()` 函数,允许我们发出自定义事件。当你发出一个事件时,你需要传递事件的名称,以及(可选地)包含要传递给每个监听器的附加信息的对象。这些附加数据将在事件对象的 `detail` 属性中。 + +> **备注:** Svelte 中的自定义事件与常规 DOM 事件共享相同的 API。此外,你可以通过指定 `on:event` 通过将事件向上传递给父组件,而无需指定处理器。 + +我们将编辑我们的 `Todo` 组件,以发出一个 `remove` 事件,并传递被删除的待办事项作为附加信息。 + +1. 首先,在 `Todo` 组件的 `