- Ember.js 指南
- 入门指南 - 介绍
- 入门指南 - 应用规划
- 入门指南 - 创建静态页面
- 入门指南 - 获取Ember.js和相应依赖
- 入门指南 - 添加第一个路由与模板
- 入门指南 - 建立模型
- 入门指南 - 使用静态数据
- 入门指南 - 显示模型数据
- 入门指南 - 显示模型的完成状态
- 入门指南 - 创建新的模型实例
- 入门指南 - 标记模型为完成或未完成
- 入门指南 - 显示未完成待办事项的数量
- 入门指南 - 切换显示和编辑状态
- 入门指南 - 接受修改
- 入门指南 - 删除模型
- 入门指南 - 添加子路由
- 入门指南 - 显示未完成待办事项
- 入门指南 - 显示已完成待办事项
- 入门指南 - 显示所有待办事项
- 入门指南 - 添加移除所有已完成待办事项的按钮
- 入门指南 - 提示所有待办事项已完成
- 入门指南 - 切换已完成和未完成待办事项
- 入门指南 - 更换FixtureAdapter
- 获取 Ember - 获取Ember
- 概念 - 核心概念
- 概念 - 命名惯例
- 对象模型 - 类与实例
- 对象模型 - 计算属性
- 对象模型 - 计算属性和带@each的集合数据
- 对象模型 - 观察器
- 对象模型 - 绑定
- 对象模型 - 重新打开类和实例
- 对象模型 - 绑定,观察器,计算属性:如何选择?
- 应用 - 介绍
- 模板 - 应用模板
- 模板 - Handlebars基础
- 模板 - 条件表达式
- 模板 - 显示项目列表
- 模板 - 切换作用域
- 模板 - 绑定元素属性
- 模板 - 绑定元素类名称
- 模板 - 链接
- 模板 - 操作
- 模板 - 输入助手
- 模板 - 开发助手
- 模板 - 用助手来渲染
- 模板 - 编写助手方法
- 路由 - 介绍
- 路由 - 定义路由
- 路由 - 生成的对象
- 路由 - 指定路由的模型
- 路由 - 设置控制器
- 路由 - 渲染模板
- 路由 - 重定向
- 路由 - 指定地址API
- 路由 - 查询参数
- 路由 - 异步路由
- 路由 - 加载中/错误子状态
- 路由 - 阻止和重试过渡
- 组件 - 介绍
- 组件 - 定义组件
- 组件 - 传递属性
- 组件 - 包裹内容
- 组件 - 自定义组件元素
- 组件 - 使用Action处理用户交互
- 组件 - 从组件发送操作给应用
- 控制器 - 介绍
- 控制器 - 代表单一模型
- 控制器 - 代表多模型
- 控制器 - 管理控制器间的依赖
- 模型 - 介绍
- 模型 - 定义模型
- 模型 - 创建和删除记录
- 模型 - 将记录推入仓库
- 模型 - 持久化记录
- 模型 - 查询记录
- 模型 - 使用记录
- 模型 - 使用Fixture
- 模型 - 连接HTTP服务器
- 模型 - 处理元数据
- 模型 - 自定义适配器
- 模型 - 常见问题
- 视图 - 介绍
- 视图 - 定义视图
- 视图 - 处理事件
- 视图 - 在模板中插入视图
- 视图 - 为视图添加布局
- 视图 - 自定义视图元素
- 视图 - 内置视图
- 视图 - 手动管理视图层级
- 枚举 - 介绍
- 测试 - 介绍
- 测试 - 集成测试
- 测试 - 测试助手
- 测试 - 测试用户交互
- 测试 - 单元测试
- 测试 - 单元测试基础
- 测试 - 测试组件
- 测试 - 测试控制器
- 测试 - 测试路由
- 测试 - 测试模型
- 测试 - 自动化测试
- 配置Ember.js - 禁用基本类型扩展
- 配置Ember.js - 嵌入式应用
- 配置Ember.js - 特性标识
- Cookbook - 简介
- Cookbook - 用户界面与交互
- Cookbook - 事件处理和数据绑定
- Cookbook - 助手与组件
- Cookbook - 使用对象
- 理解Ember.js - 视图层
- 理解Ember.js - 管理异步
- 理解Ember.js - 模板自动更新
- 理解Ember.js - 调试
- 理解Ember.js - 运行循环
路由 - 指定路由的模型
英文原文: http://emberjs.com/guides/routing/specifying-a-routes-model/
指定路由的模型
应用中的模板背后是由模型来支撑的。那么模板是如何知道需要显示哪些模型的呢?
例如,如果有一个photos
模板,那么它是如何知道应该渲染哪一个模型的呢?
这正是Ember.Route
的工作之一。通过定义一个与模板同名的,并实现其model
方法的路由,是一种指定模板需要渲染的模型的方法。
例如,为了给photos
模板提供一些模型数据,可以定义一个App.PhotosRoute
对象:
1 2 3 4 5 6 7 8 9 10 11 | App.PhotosRoute = Ember.Route.extend({ model: function() { return [{ title: "Tomster", url: "http://emberjs.com/images/about/ember-productivity-sm.png" }, { title: "Eiffel Tower", url: "http://emberjs.com/images/about/ember-structure-sm.png" }]; } }); |
异步加载的模型
在上述例子中,模型数据在model
钩子中是被同步返回的。也就是说数据是立即可用的,应用不需要花时间等待数据加载,例子中model
钩子里面直接返回了硬编码的一组数据。
当然这与实际的情况并不总是吻合。更常见的是数据并不是同步的,而是需要通过网络异步加载。例如,可能需要通过一个服务端的JSON API来获取照片列表。
在数据是异步加载时,在model
钩子里面只需要返回一个承诺,Ember就会等待承诺履行后才开始渲染模板。
如果对承诺不熟悉,可以姑且将其认为承诺就是代表了最终加载的数据的对象。例如,使用jQuery的getJSON
方法,该方法就返回一个代表最终从网络加载的JSON的承诺。Ember使用这个承诺对象知道何时拥有了足够用来渲染的数据。
更多关于承诺的详细介绍,请参看异步路由指南中的关于承诺部分。
下面看一个实际的例子。这里有一个从GitHub上获取最近的Ember.js的PR的路由:
1 2 3 4 5 | App.PullRequestsRoute = Ember.Route.extend({ model: function() { return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls'); } }); |
为了使得代码更加易读,这个例子看上去跟同步的没有什么两样,但是实际上它是异步完成的。这是因为jQuery的getJSON()
方法返回了一个承诺。Ember会检测到model
钩子返回的是一个承诺,然后一直等待直至承诺被履行时才渲染pullRequests
模板。
(更多关于jQuery的XHR函数,请查看jQuery文档jQuery.ajax。)
因为Ember支持承诺,这使得Ember可以与所有采用承诺作为公共API一部分的持久化库一起工作。此外,利用关于承诺的内置惯例,还可以让代码变得更加清晰。
例如,假设需要修改上例,让模板只显示最近三个PR。通过采用承诺链,可以在将数据传递给模板之前修改请求返回的JSON:
1 2 3 4 5 6 7 8 | App.PullRequestsRoute = Ember.Route.extend({ model: function() { var url = 'https://api.github.com/repos/emberjs/ember.js/pulls'; return Ember.$.getJSON(url).then(function(data) { return data.splice(0, 3); }); } }); |
使用模型设置控制器
model
钩子返回的数据上到底发生了些什么呢?
在默认情况下,model
钩子返回的值,会设置为关联的控制器的model
属性。例如,如果App.PostsRoute
通过model
钩子返回了一个对象,这个对象会设置为App.PostsController
的model
属性。
(模板是如何知道该使用哪个模型进行渲染的呢?模板通过查找其关联的控制器的model
属性来进行渲染。例如,photos
模板将会使用App.PhotosController
的model
属性来进行渲染。)
查看设置控制器指南一节,可以知道如何改变这个缺省行为。注意,如果重写了这一缺省行为,且未给控制器设置model
属性,那么模板就无法获得用来渲染的数据。
动态模型
有的路由总是显示相同的模型。例如,/photos
路由将总是显示应用中所有照片的列表。用户离开该路由,然后再回来这个模型也不会发生改变。
然而,有的路由却需要根据用户的交互来显示不同的模型。例如,照片浏览器应用。/photos
路由将使用照片列表作为模型来渲染photos
模板,这个模型不会改变。但是当用户点击一个特定的照片,那么需要在photo
模板中显示被选定的照片。如果用户回头点击另外一张不同的照片,这时需要一个不同的模型来渲染photo
模板。
在这种情况下,需要在URL中不仅包含要渲染哪一个模板,还要知道使用哪一个模型。
在Ember中,通过动态段来定义路由可以完成该任务。
一个动态段是URL的一部分,动态段最终将被模型的ID取代。动态段的定义以分号(:
)开始。照片例子中photo
路由可以如下所示进行定义:
1 2 3 | App.Router.map(function() { this.resource('photo', { path: '/photos/:photo_id' }); }); |
在上例中,photo
路由有一个动态段:photo_id
。当用户进入photo
路由来显示一个特定的照片模型时(通常是通过{{link-to}}
助手),模型的ID会被自动的添加到URL中。
查看链接可以查看更多关于使用{{link-to}}
助手,传递一个模型,然后链接到指定路由。
例如,如果使用一个id
属性值为47
的模型,过渡到photo
路由,那么在用户浏览器中的URL会更新为:
1 | /photos/47 |
那么如果用户直接通过浏览器输入一个包含动态段的URL会发生什么呢?例如,用户可能重新加载页面,或者发送一个链接给朋友等。这时,由于应用是重新启动的,用于显示的Javascript模型对象已经不存在,所能得到的就只有模型的ID。
幸运的是,Ember会从URL中抽出动态段部分,并将其作为第一个参数,传递给model
钩子:
1 2 3 4 5 6 7 8 9 | App.Router.map(function() { this.resource('photo', { path: '/photos/:photo_id' }); }); App.PhotoRoute = Ember.Route.extend({ model: function(params) { return Ember.$.getJSON('/photos/'+params.photo_id); } }); |
在有动态段的路由的model
钩子中,需要通过传入的ID(比如47
或者post-slug
),转换为需要用来渲染模板的模型。在上面的例子中,使用了照片的ID(params.photo_id
)来构造一个URL,来获取照片的JSON格式表示。一旦有了URL,就可以使用jQuery来获取一个表示JSON模型数据的一个承诺。
注意:一个具有动态段的路由只有在通过URL访问的时候,model
钩子才会被调用。如果路由是从一个跳转进入的(例如:使用Handlebars的link-to助手时),模型上下文已经准备好了,因此model
钩子这时不会被执行。没有动态段的路由其model
钩子每次都会被执行。
Ember Data
许多Ember开发者都会使用一个模型库来处理查询、保存记录,这样比手动处理AJAX调用要简单很多。特别是使用一个可以缓存已经加载记录的模型库,会大大提升应用的性能。
为Ember定制的一个流行的模型库是Ember Data。需要了解更多关于使用Ember Data来管理模型的内容,可以查看模型指南一章。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论