### [拥抱余烬:第 4 部分](https://www.prosaas.cn/article/5505) **Published:** 2023-09-02T12:37:02 **Author:** 5201314 **Excerpt:** 在我之前的教程中,我介绍了如何使用 来定义模型并使用数据集。在本节中,我们将更仔细地了解 Ember 如何使用…  在我之前的教程中,我介绍了如何使用 `Ember.Object` 来定义模型并使用数据集。在本节中,我们将更仔细地了解 Ember 如何使用 Handlebars 模板框架来定义应用的用户界面。 * * * ## 客户端模板 大多数服务器端开发人员习惯于使用模板来定义将动态填充的标记。如果您曾经使用过 ASP.NET、ColdFusion、PHP 或 Rails,那么您肯定知道我在说什么。 JavaScript 客户端模板最近确实开始流行,特别是因为它专注于构建更多类似桌面的体验。这意味着更多的处理是在客户端完成的,数据主要通过服务器端 API 请求拉取。 我记得不久前 jQuery 模板插件首次发布时写过有关客户端模板的文章。近三年后,它仍然是我博客上阅读量最大的帖子,表明人们对客户端模板的兴趣有多么高涨。从那时起,许多其他框架已经发布,提供了丰富的功能和支持社区。 Handlebars 是更流行的选项之一,也是 Ember 项目选择的框架来满足其模板需求。这是有道理的,因为 Handlerbars 是由 Ember.js 联合创始人兼核心团队成员 Yehuda Katz 创建的。但请注意,我不打算在模板框架之间进行比较,我将严格关注 Handelbars,因为这是 Ember.js 默认使用的。 在之前的文章中,我在代码中展示了一些非常基本的模板: 有两件事很突出,那就是脚本标签的类型声明和大括号,它们充当 Handlebars 将作用的表达式的分隔符。这是非常典型的语法,我将很快详细讨论,您将在构建 Ember 模板时一致地使用它。 * * * ## 语法 尽管 Handlebars 使用特殊语法,但归根结底,您实际上主要使用标准 HTML 标记。 Handlebars 用于将内容注入到此标记中,以将数据呈现给用户。它通过解析分隔表达式并将其替换为您要求 Handlebars 使用的数据来实现此目的。对于 Ember,Handlebars 提供挂钩,Ember 使用它们。该数据通常来自您的控制器(请记住,控制器充当模型的接口)。 任何模板首先需要的是脚本标记定义。大多数人可能已经定义了脚本标签来加载 JavaScript 库。事实上,您已经这样做了,将 Handlebars 加载到您的 Ember 项目中: 与使用它来定义模板略有不同。首先,我们指定“text/x-handlebars”的 `type` 属性。浏览器会忽略此 `type`,但保留文本可供检查,并允许 Ember 识别应用程序内的模板。此外,Ember 使用名为“data-template-name”的数据属性,Ember 可以使用该属性将应用程序的特定部分与模板关联起来。例如,以下声明定义了一个名为“employee”的模板: 当您的应用程序启动时,Ember 会扫描 DOM 中的 `type="text/x-handlebars`,编译它找到的模板,并将它们存储在 Ember 对象的一个属性中,该属性名为 `Ember.TEMPLATES` 并使用它找出为给定路线呈现的内容。这就是为什么遵循 Ember 的命名约定如此重要。在上面的示例中,此模板将自动关联到您在应用程序中创建的员工路线和控制器。同样,我可以'不必过多强调这些命名约定将如何使您的开发变得更加容易。 Ember 依赖 URL 来确定需要使用的资源和需要渲染的模板。假设您有一个 URL 为“/profile”的个人资料页面。您将拥有一个名为 `profile` 的资源,它将加载该 URL 的特定资源(如路由对象),并且您还将拥有一个同名的模板。我们在 Ember 系列的第 2 部分中回顾了定义资源和路由对象,因此如果您不确定我正在讨论的内容,请务必跳回那里重新了解一下。 当您访问该 URL 时,Ember 知道它需要加载这些资源并解析您定义的模板。它通过其命名约定来执行此操作,知道因为您转到“/profile”,所以它需要加载 `profile` 中定义的资源,并呈现名为 `data-template-name="profile"` 的模板。 - **路线:**配置文件路线 - **控制器:** ProfileController - **模板:**个人资料(注意是小写) 再次查看命名约定,您会发现路由、控制器和模板都使用相同的 URL 名称绑定在一起,但模板拼写为小写。这使得 Ember 能够在幕后管理一切,而无需进行大量接线。 还需要注意的是,如果您声明的模板没有 `data-template-name` 属性,Ember 将假定它是应用程序范围的模板 - 通常用作站点范围模板来创建用户界面元素,例如页眉、页脚和导航。如果您没有为应用程序甚至资源(例如 URL)显式定义模板,Ember 会自动为您执行此操作,以确保应用程序的稳定性和一致性。 * * * ## 表达式 下一步是包含您的标记和用于表示数据的分隔表达式。表达式通过双花括号进行分隔,这使得它们可以通过从控制器传递的数据轻松识别和解析。这是一个例子: 在这种情况下,`{{firstName}}` 和 `{{lastName}}` 表达式将被 Ember 解析并替换为实际数据。此外,Ember 设置了观察者,以便当您的数据发生变化时,您的模板会自动更新,并将更新反映给应用程序的用户。 到目前为止,我已经向您展示了一个非常简单的示例,但要点是: - Ember 使用特殊的类型属性来定义模板。 - 模板使用标准标记以及分隔表达式,这些表达式在客户端进行解析。 - 这些模板具有 Handlebars 的完整功能集。 - Ember 设置观察者来动态更新您的用户界面数据(当用户界面数据发生变化时)。 这为您构建用户界面的方式提供了很大的灵活性。让我们继续看看可用的功能。 * * * ## 高级表达式 请记住,Ember 利用了 Handlebars,因此您可以在此处访问其完整的表达式。为了使几乎任何东西变得有用,条件表达式是必须的;车把提供了相当多的选择。 假设我有一个如下所示的 JSON 数据集: "items": \[{ "title": "Tearable Cloth Simulation in JavaScript", "url": "http://codepen.io/stuffit/pen/KrAwx", "id": 5592679, "commentCount": 20, "points": 127, "postedAgo": "1 hour ago", "postedBy": "NathanKP" }, { "title": "Netflix now bigger than HBO", "url": "http://qz.com/77067/netflix-now-bigger-than-hbo/", "id": 5592403, "commentCount": 68, "points": 96, "postedAgo": "2 hours ago", "postedBy": "edouard1234567" } 如果我想确保 `title` 数据可用,我可以使用 `#if` 表达式添加条件“if”语句: {{#if item.title}}