进入Ember.js的第三部分:深入探索
我希望您开始认识到 Ember.js 是一个强大但固执己见的框架。我们只触及了它的表面;在我们构建真正有用的东西之前,还有更多东西需要学习!我们将继续使用 Ember 入门套件。在本系列的这一部分中,我们将回顾如何访问和管理 Ember 中的数据。
使用数据
在上一篇文章中,我们使用了在控制器中定义的一组静态颜色名称:
App.IndexRoute = Ember.Route.extend({ setupController: function(controller) { controller.set('content', ['red', 'yellow', 'blue']); } });
这允许控制器将数据公开给索引模板。这对于演示来说很可爱,但在现实生活中,我们的数据源不会是硬编码的数组。
这就是模型的用武之地。模型是应用程序使用的数据的对象表示。它可以是一个简单的数组或从 RESTful JSON API 动态检索的数据。通过引用模型的属性来访问数据本身。因此,如果我们看一下这样的结果:
{ "login": "rey", "id": 1, "age": 45, "gender": "male" }
模型中公开的属性是:
- login
- 手
- age
- gender
通过引用模型的属性来访问数据本身。
正如您从上面的代码中看到的,您可以定义一个静态存储,但大多数时候您将使用 Ember.Object 来定义模型。通过子类化 Ember.Object,您将能够返回数据(例如:通过 Ajax 调用)并定义您的模型。虽然您可以在控制器中显式设置数据,但始终建议您创建一个模型,以便遵守关注点分离和代码组织最佳实践。
或者,您可以使用名为 Ember Data 的姊妹框架。它是一个类似 ORM 的 API 和持久性存储,但我需要强调的是,在撰写本文时它正处于不断变化的状态。它有很大的潜力,但是此时使用 Ember.Object 更安全。 Discourse 的联合创始人 Robin Ward 撰写了一篇关于在没有 Ember 数据的情况下使用 Ember 的精彩博客文章。它概述了他们的流程,我将为您分解。
定义模型
在下面的示例中,我将使用非官方的 Hacker News API 从新闻资源中提取基于 JSON 的数据。该数据将存储在我的模型中,稍后由控制器用来填充模板。如果我们查看从 API 返回的数据,我们就可以了解我们将使用的属性:
{ "nextId": null, "items": [{ "title": "Docker, the Linux container runtime: now open-source", "url": "http://docker.io", "id": 5445387, "commentCount": 39, "points": 146, "postedAgo": "2 hours ago", "postedBy": "shykes" }, { "title": "What\u0027s Actually Wrong with Yahoo\u0027s Purchase of Summly", "url": "http://hackingdistributed.com/2013/03/26/summly/", "id": 5445159, "commentCount": 99, "points": 133, "postedAgo": "2 hours ago", "postedBy": "hoonose" }, ], "version": "1.0", "cachedOnUTC": "\/Date(1364333188244)\/" }
我想使用 items 属性,其中包含所有标题和故事信息。如果您使用过 SQL 数据库,请将 items 的每个元素视为一条记录,并将属性名称(即:title、url、id 等)视为字段名称。理解布局很重要,因为这些属性名称将用作模型对象的属性,这是创建模型的完美衔接。
Ember.Object 是所有 Ember 对象的主要基类,我们将对其进行子类化以使用其 extend() 方法创建我们的模型。
为此,我们将在定义 App.IndexRoute 的代码之后立即将以下代码添加到 js/app.js 中:
App.Item = Ember.Object.extend();
App.Item 用作黑客新闻数据的模型类,但它没有检索或操作该数据的方法。因此,我们需要定义这些:
App.Item.reopenClass({ all: function() { return $.getJSON("http://api.ihackernews.com/page?format=jsonp&callback=?").then(function(response) { var items = []; response.items.forEach( function (item) { items.push( App.Item.create(item) ); }); return items; }); } });
让我们分解一下这段代码。首先,我们使用 Ember 的 reopenClass() 方法将新方法添加到 App.Item 类中,然后向其传递一个包含我们所需方法的对象。对于此示例,我们只需要一个名为 all() 的方法:它返回黑客新闻首页的所有标题。因为 jQuery 是 Ember 协议的一部分,所以我们可以使用它简单的 Ajax API。 API使用JSONP返回JSON数据;所以,我可以使用 $.getJSON() 向以下位置发出请求:
$.getJSON("http://api.ihackernews.com/page?format=jsonp&callback=?")
“回调=?”告诉 jQuery 这是一个 JSONP 请求,并且数据(一旦检索到)将传递到使用 jQuery 的 Promise 功能定义的匿名回调处理程序:
.then(function(response) {...});
我可以轻松地将 JSON 数据注入 Ember 对象。
response 参数包含 JSON 数据,允许您循环记录并使用 App.Item 的实例更新本地 items 数组。最后,当 all() 执行时,我们返回新填充的数组。说了这么多,我总结一下:
- 通过使用 extend() 子类化 Ember.Object 来创建新模型类。
- 使用 reopenClass() 添加模型方法。
- 进行 Ajax 调用来检索您的数据。
- 循环数据,创建 Item 对象并将其推入数组中。
- 方法执行时返回数组。
如果您刷新index.html,您将看到没有任何变化。这是有道理的,因为模型刚刚被定义;我们还没有访问过它。
公开您的数据
控制器的作用类似于代理,使您可以访问模型的属性并允许模板访问它们以便动态渲染显示。除了从关联模型访问属性之外,控制器还可以存储需要持久保存的其他应用程序属性,而无需保存到服务器。
目前,我们的应用程序具有以下控制器(定义静态数据集的控制器):
App.IndexRoute = Ember.Route.extend({ setupController: function(controller) { controller.set('content', ['red', 'yellow', 'blue']); } });
我们可以使用 model 方法(又名模型钩子)直接将我们的模型与 App.IndexRoute 关联起来:
App.IndexRoute = Ember.Route.extend({ model: function() { return App.Item.all(); } });
请记住,如果您自己没有显式定义控制器,那么 Ember 会定义您的控制器,这就是本例中发生的情况。
在幕后,Ember 创建 IndexController 作为 Ember.ArrayController 的实例,并使用 model 方法中指定的模型。
现在我们只需要更新索引模板即可访问新属性。打开index.html,我们可以看到以下Handlebars模板代码:
{{#each item in model}} <li>{{item}}</li> {{/each}}
通过一个小更改(添加 title 属性),我们可以立即看到从 Hacker News API 返回的标题:
{{item.title}}
如果您现在刷新浏览器,您应该会看到类似以下内容的内容:
<h3>Welcome to Ember.js</h3> <ul><li>Persona is distributed. Today.</li> <li>21 graphs that show America's health-care prices are ludicrous</li> <li>10 000 concurrent real-time connections to Django</li> <li>Docker, the Linux container runtime: now open-source</li> <li>Let's Say FeedBurner Shuts Down…</li></ul>
如果您想显示更多信息,只需添加更多属性:
{{item.title}} - {{item.postedAgo}} by {{item.postedBy}}
刷新即可查看您所做的更新。这就是 Handlebars 的魅力所在;它使得向用户界面添加新数据元素变得微不足道。
正如我之前提到的,控制器还可以用于定义需要在应用程序的整个生命周期中保留的静态属性。例如,我可能想保留某些静态内容,如下所示:
App.IndexController = Ember.ObjectController.extend({ headerName: 'Welcome to the Hacker News App', appVersion: 2.1 });
在这里,我将 Ember.ObjectController 子类化,为我的 index 路由和模板创建一个新的控制器。我现在可以转到 index.html 并更新我的模板以替换以下内容:
<h2>Welcome to Ember.js</h2>
与:
<h2>{{headerName}}</h2>
模型是应用程序使用的数据的对象表示。
Handlebars 将采用我的控制器中的指定属性,并用其同名值动态替换 {{headerName}} 占位符。强调两件事很重要:
- 通过遵守 Ember 的命名约定,我无需进行任何接线即可将控制器与索引模板一起使用。
- 即使我显式创建了 IndexController,Ember 也足够聪明,不会覆盖通过路由关联的现有模型。
这是非常强大且灵活的东西!
下一步...模板
在 Ember 中处理数据并不困难。实际上,最困难的部分是使用网络上大量的各种 API。
事实上,我可以轻松地将 JSON 数据输入到 Ember 对象中,这使得管理变得更加容易 — 尽管我从来都不是客户端大型数据集的忠实粉丝,尤其是当表示为对象时.
这是我必须做更多测试的事情,我希望 Ember Data 能让这一切变得微不足道。
话虽如此,我在本文中简要介绍了模板。它们非常重要……以至于我想在自己的文章中讨论这个主题。因此,在下一篇文章中,我们将介绍如何利用 Handelbars 构建用户界面,并深入了解模板框架提供的各种指令。
进入Ember.js的第三部分:深入探索的详细内容,更多请关注红帽云邮其它相关文章!