Ember.js 概念详解–路由器

官方文档地址:http://emberjs.com/guides/routing/

由于是从word考过来的,格式不是太好,大家可以直接去下载我的完整word。里面除了翻译还有原创内容。

http://download.csdn.net/detail/kevinwon1985/5230326

—————————————————————————————————-

用户与你的应用交互,会产生很多不同的状态。框架提供了管理这些状态的有用的工具。

在框架中,应用中每个可能的状态都体现在URL上,并且由路由器负责管理这些状态。路由器下有一组路由,每个路由对应一个状态,也就是一个URL。

当你的应用启动,路由器负责显示模版,加载数据和设置应用状态。它通过匹配当前的URL到你定义的路由来完成工作。

3.3.1 配置路由器

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。

3.3.2 定义路由

你可以通过创建一个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

3.3.3 资源

你可以用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
↳PostsIndexController
PostsRoute
↳PostsIndexRoute
posts
↳posts/index
/posts/new posts.new PostsController
↳PostsNewController
PostsRoute
↳PostsNewRoute
posts
↳posts/new
 

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用形容词或者动词修饰这个名词。

3.3.4 动态参数

动态参数以“:”开头,后面跟着参数名。

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方法可以省略。

3.3.5 嵌套资源

你不能在路由中嵌套路由,但是可以在资源中嵌套资源。

这个路由器生成以下路由:

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

3.3.6 指定模型

如果你没有动态参数,你需要自己实现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)。

3.3.7 设置控制器

在框架中,模版从控制器中获取信息并显示出来。

框架中有两个内置的控制器,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);

}

});

3.3.8 渲染模版

路由的一个重要工作就是渲染指定的模版到屏幕。

默认的,会渲染关联的模版到最近的父模版的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控制器,可以直接传控制器实例

});

}

});

3.3.9 重定向

如果你先重定向到另外一个路由,需要实现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)还是会执行。

3.3.10指定url类型

路由器默认使用浏览器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’

});

标签