官方文档地址:http://emberjs.com/guides/routing/
由于是从word考过来的,格式不是太好,大家可以直接去下载我的完整word。里面除了翻译还有原创内容。
http://download.csdn.net/detail/kevinwon1985/5230326
----------------------------------------------------------------------------------------------------
用户与你的应用交互,会产生很多不同的状态。框架提供了管理这些状态的有用的工具。
在框架中,应用中每个可能的状态都体现在URL上,并且由路由器负责管理这些状态。路由器下有一组路由,每个路由对应一个状态,也就是一个URL。
当你的应用启动,路由器负责显示模版,加载数据和设置应用状态。它通过匹配当前的URL到你定义的路由来完成工作。
App.Router.map(function() { this.route("about", { path: "/about" }); this.route("favorites", { path: "/favs" }); }); |
当用户访问 / ,框架会渲染 index 模版。访问 /about 渲染 about 模版,访问 /favs 渲染favorites 模版。
当path与路由名相同,就可以省略path。上例等价于
App.Router.map(function() { this.route("about"); this.route("favorites", { path: "/favs" }); }); |
在你的模版里,可以通过{{linkTo}}标记指定路由名在路由间导航。(/路径的名字是index)
{{#linkTo"index"}}<imgclass="logo">{{/linkTo}} <nav> {{#linkTo"about"}}About{{/linkTo}} {{#linkTo"favorites"}}Favorites{{/linkTo}} </nav> |
关于{{linkTo}}的详细请看3.4.5。
你可以通过创建一个Ember.Route的子类来自定义路由的行为。例如,定制当用户访问 / 时的行为,创建App.IndexRoute
App.IndexRoute = Ember.Route.extend({ setupController: function(controller) { // Set the IndexController's `title` controller.set('title', "My App"); } }); |
IndexController是index模版的首选上下文。现在你已经设置了title,你可以在模版中使用
<!-- get the title from the IndexController --> <h1>{{title}}</h1> |
(如果你没有定义App.IndexController,框架会自动创建一个。)
框架会根据传给this.route的名字来自动计算路由、控制器、模版的名字。
URL | Route Name | Controller | Route | Template |
/ | index | IndexController | IndexRoute | index |
/about | about | AboutController | AboutRoute | about |
/favs | favorites | FavoritesController | FavoritesRoute | favorites |
你可以用resources来定义一个路由组。
和this.route一样。path与资源名一样的时候,可以省略path,所以上面的等价于
这个路由器会创建四个路由
URL | Route Name | Controller | Route | Template |
/ | index | IndexController | IndexRoute | index |
N/A | posts1 | PostsController | PostsRoute | posts |
/posts | posts.index | PostsController | PostsRoute | posts |
/posts/new | posts.new | PostsController | PostsRoute | posts |
1跳转或者链接到posts的行为会被自动重定向到posts.index
注意:如果你配置一个资源但是不提供一个function,那么框架不会创建resource.index路由。这种情况下,/resource会使用ResourceRoute,ResourceController和resource模版。这时this.resource等价于this.route
资源中内嵌的路由的全名要把资源名加在它的名字前(posts.new不是new)。如果你要跳转到一个路由(无论是通过transitionTo或者{{#linkTo}}),确保使用全名(posts.new不是new)。
访问 / 时,跟上面将的规则一样,会渲染 index 模版。
访问 /posts 就有些不一样了。首先会渲染 posts 模版。然后会渲染posts/index 模版到posts模版的outlet中。
访问 posts/new 也会先渲染 posts 模版。然后会渲染 posts/new 模版到posts模版的outlet中。
注意:你应该用名词表示一个资源,资源内的route用形容词或者动词修饰这个名词。
动态参数以“:”开头,后面跟着参数名。
App.Router.map(function() { this.resource('posts'); this.resource('post', {path:'/post/:post_id' }); });
App.PostRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); }, serialize: function(post) { return { post_id: post.get('id') }; } }); |
你的路由的model
方法传递参数:post_id
到模型里。serialize
方法转换模型对象到URL参数中。 (例如:计算一个模型的链接的时候).
因为这种模式很常见,所以路由提供了默认的处理。
· 如果你的动态参数以"_id"
结束,model
方法会转换参数post_id
的
第一部分为应用的命名空间下的一个模型类(post
变成App.Post
)。然后调用类的find
方法,并传入动态参数值。
· 默认的serialize方法会用模型的id属性值给动态参数赋值。所以上面的serialize方法可以省略。
你不能在路由中嵌套路由,但是可以在资源中嵌套资源。
这个路由器生成以下路由:
URL | Route Name | Controller | Route | Template |
/ | index | App.IndexController | App.IndexRoute | index |
N/A | post | App.PostController | App.PostRoute | post |
/post/:post_id2 | post.index | App.PostIndexController | App.PostIndexRoute | post/index |
/post/:post_id/edit | post.edit | App.PostEditController | App.PostEditRoute | post/edit |
N/A | comments | App.CommentsController | App.CommentsRoute | comments |
/post/:post_id/comments | comments.index | App.CommentsIndexController | App.CommentsIndexRoute | comments/index |
/post/:post_id/comments/new | comments.new | App.CommentsNewController | App.CommentsNewRoute | comments/new |
如果你没有动态参数,你需要自己实现model方法,指定使用哪个模型关联匹配的url。
App.Router.map(function() { this.resource('posts'); }); App.PostsRoute = Ember.Route.extend({ model: function() { return App.Post.find(); } }); |
如果用到动态参数,你会想要通过参数来获取模型。
App.Router.map(function() { this.resource('post', {path:'/posts/:post_id' }); });
App.PostRoute = Ember.Route.extend({ model: function(params) { return App.Post.find(params.post_id); } }); |
因为这种模式太常见,上面的model方法就是默认行为。
例如,你的动态参数是post_id,框架会使用_前的post为模型也就是App.Post。除非你重写model方法,否则路由会自动返回App.Post.find(params.post_id)。
在框架中,模版从控制器中获取信息并显示出来。
框架中有两个内置的控制器,Ember.ObjectController和 Ember.ArrayController。它们很好用。它们代理模型的属性,并且有自己的额外的属性,最终传递给模版。
在setupController方法中,设置控制器的content属性来代理模型。
App.Router.map(function() { this.resource('post', {path:'/posts/:post_id' }); });
App.PostRoute = Ember.Route.extend({ setupController:function(controller, model) { controller.set('content', model); } }); |
setupController方法接收两个参数,第一个是该路由关联的控制器,第二个是model方法返回的模型。上面的例子中,PostRoute的关联控制器是App.PostController的实例。
setupController方法的默认行为就是上面代码。所以你可以省略上面的setupController。
如果你不只是想操作关联的控制器,可以用controllerFor方法。
App.PostRoute = Ember.Route.extend({ setupController: function(controller, model) { this.controllerFor('topPost').set('content', model); } }); |
路由的一个重要工作就是渲染指定的模版到屏幕。
默认的,会渲染关联的模版到最近的父模版的outlet中,并使用关联的控制器。
App.PostsRoute = Ember.Route.extend({ renderTemplate: function(controller, model) { this.render(); } }); |
包含全部的参数的代码如下
App.PostsRoute = Ember.Route.extend({ renderTemplate:function(controller, model) { this.render('posts', { //模版名,默认是关联的posts into:undefined, //父模版,没有就是undefined outlet:'main', //outlet名字,默认是main,也就是父模版中的唯一的没有命名outlet controller:'posts'//默认是PostsController控制器,可以直接传控制器实例 }); } }); |
如果你先重定向到另外一个路由,需要实现redirect方法。
App.Router.map(function() { this.resource('posts'); });
App.IndexRoute = Ember.Route.extend({ redirect: function() { this.transitionTo('posts'); } }); |
你也可以基于应用关状态添加重定向条件。
App.Router.map(function() { this.resource('topCharts',function() { this.route('choose', {path:'/' }); this.route('albums'); this.route('songs'); this.route('artists'); this.route('playlists'); }); }); App.TopChartsChooseRoute = Ember.Route.extend({ redirect: function() { var lastFilter = this.controllerFor('application').get('lastFilter'); this.transitionTo('topCharts.' + lastFilter ||'songs'); } }); // Superclass to be used by all of the filter routes below App.FilterRoute = Ember.Route.extend({ enter: function() { var controller = this.controllerFor('application'); controller.set('lastFilter',this.templateName); } }); App.TopChartsSongsRoute = App.FilterRoute.extend(); App.TopChartsAlbumsRoute = App.FilterRoute.extend(); App.TopChartsArtistsRoute = App.FilterRoute.extend(); App.TopChartsPlaylistsRoute = App.FilterRoute.extend(); |
如果路由的redirect钩子方法没有重定向到另外的路由,余下的钩子方法(model,setupController,renderTemplate)还是会执行。
路由器默认使用浏览器url的哈希值来加载应用的初始状态,并且在url地址发生改变是同步状态。目前,这些是通过浏览器的hashchange来实现的。
看下面的路由器。当你访问/#/posts/new会关联到进入posts.new路由。
App.Router.map(function() { this.resource('posts',function() { this.route('new'); }); }); |
如果你先使用地址/posts/new替代/#/posts/new,你需要告诉路由使用浏览器的history API。
App.Router.reopen({ location: 'history' }); |
如果你不想浏览器的url与你的应用交互,可以完全禁用location API。这有助于你测试,或者在不想改变url的情况下用路由器管理应用状态(例如当把应用嵌入到一个更大的页面中)。
App.Router.reopen({ location: 'none' }); |
上一篇: Ember.js 指引--命名约定