发布于 2015-08-18 16:37:40 | 837 次阅读 | 评论: 0 | 来源: 网络整理
当启动你的应用时,路由器会负责展示模板,载入数据,以及设置应用状态等任务。 这些都是通过将当前的URL与你定义的路由进行匹配来实现的。
1 2 3 4 |
App.Router.map(function() {
this.route("about", { path: "/about" });
this.route("favorites", { path: "/favs" });
});
|
现在当用户访问/about时,Ember.js就会渲染about的模板。访问/favs将渲染favorites的模板。
提示:如果路径(path)的名字跟路由(route)的名字是一样的话,你可以不用写上路径。 所以下面的示例跟上面的是相同的。
1 2 3 4 |
App.Router.map(function() {
this.route("about");
this.route("favorites", { path: "/favs" });
});
|
在模板里面,你可以用{{link-to}}来导向路由,这需要用到你在route方法中定义的名字 (对于/来说,名字就是index)。
1 2 3 4 5 6 |
{{#link-to 'index'}}<img class="logo">{{/link-to}}
<nav>
{{#link-to 'about'}}About{{/link-to}}
{{#link-to 'favorites'}}Favorites{{/link-to}}
</nav>
|
{{link-to}}助手会在链接上面加上active的类名(class)来指出当前活跃的路由。
你也可以通过创建一个Ember.Route的子类来对路由的行为进行自定义。例如,创建 App.IndexRoute类来定义当用户访问/时会发生什么。
1 2 3 4 5 6 |
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
// Set the IndexController's `title`
controller.set('title', "My App");
}
});
|
IndexController是index模板初始的上下文环境。如果你已经设置了title, 那么你可以在模板里面使用它。
1 2 |
<!-- get the title from the IndexController -->
<h1>{{title}}</h1>
|
(如果你没有显式的声明IndexController,Ember.js会自动生成一个。)
Ember.js会自动地根据你在this.route设置的名字来找出对应的路由与控制器。
| URL | Route Name | Controller | Route | Template |
|---|---|---|---|---|
/ |
index |
IndexController |
IndexRoute |
index |
/about |
about |
AboutController |
AboutRoute |
about |
/favs |
favorites |
FavoritesController |
FavoritesRoute |
favorites |
你可以为一个资源定义一系列的路由:
1 2 3 4 5 |
App.Router.map(function() {
this.resource('posts', { path: '/posts' }, function() {
this.route('new');
});
});
|
跟this.route一样,如果路径名称跟路由名称相同,你可以忽略路径,所以下面的路由器跟上面是等效的:
1 2 3 4 5 |
App.Router.map(function() {
this.resource('posts', function() {
this.route('new');
});
});
|
这个路由器创建了三个路由:
| 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,等效于跳转到posts.index或链接到posts.index。
注意:如果你通过this.resource定义了一个资源,但是没有提供一个函数作为参数, 那么隐式的resource.index是不会被创建的。在这种情况下,/resource只会用到 ResourceRoute,RescourceController和resource模板。
一个资源下的嵌套路由的名字会是资源名加上路由名。如果你想跳转到一个路由(用transitionTo或 {{#link-to}}),请确保使用了完整的路由名(如:post.new,而不是new)。
正如你期望的一样,访问/会渲染index模板。
访问/posts会有点不同。它会先渲染posts模板,然后再渲染posts/index模板到 posts模板的出口(outlet)上。
最后,访问/posts/new会先渲染posts模板,然后渲染posts/new模板到它的出口上。
注意:你应该使用this.resource来定义一个URL中的名词字段,而对于用来改变名词字段的形容词或动词字段 ,使用this.route来定义。例如,在上例中的代码,当指定posts(名词)的URL时,路由被定义为this.resource('posts')。然而,当定义new操作(动词)时,那么路由被定义为this.route('new')。
在路由处理器的众多职责里,其中有一个就是转换URL并将其传入模型(model)中。
例如,如果我们有一个资源this.resource('posts'),那么我们的路由处理器看起来可能像这样:
1 2 3 4 5 |
App.PostsRoute = Ember.Route.extend({
model: function() {
return this.store.find('post');
}
});
|
posts模板将会接收到一张所有可用的posts清单并将它们当做是上下文环境。
由于/posts映射到一个特定的模型上,所以我们不需要其他额外的信息就可以运行。然而,如果我们想要路由映射到某个post上,我们可不想通过在路由器中写死每一个可能的post来实现。
探究动态段
一个动态段是URL的一部分,由一个:起始,后面加上一个标示符组成。
1 2 3 4 5 6 7 8 9 10 |
App.Router.map(function() {
this.resource('posts');
this.resource('post', { path: '/post/:post_id' });
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.post_id);
}
});
|
由于这种模式很常用,所以上面的模型(model)钩子函数就是默认的行为。
例如,如果动态段是:post_id,ember.js会智能地使用App.post(加上URL提供的ID)。 特别地,如果你没有重写了模型(model),路由将会自动地返回this.store.find('post', params.post_id)。
这不是巧合,而是Ember Data所想要的。所以如果你使用Ember路由和Ember Data, 你的动态段将会以默认的方式工作。
如果模型没有在URL中使用id属性,那么应该在路由中定义一个序列化方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
App.Router.map(function() {
this.resource('post', {path: '/posts/:post_slug'});
});
App.PostRoute = Ember.Route.extend({
model: function(params) {
// the server returns `{ slug: 'foo-post' }`
return jQuery.getJSON("/posts/" + params.post_slug);
},
serialize: function(model) {
// this will make the URL `/posts/foo-post`
return { post_slug: model.get('slug') };
}
});
|
缺省的serialize方法将模型的id插入到路由的动态段中(上述的:post_id)。
你不能嵌套路由,但是你可以嵌套资源:
1 2 3 4 5 6 7 8 |
App.Router.map(function() {
this.resource('post', { path: '/post/:post_id' }, function() {
this.route('edit');
this.resource('comments', function() {
this.route('new');
});
});
});
|
这个路由器创建了五个路由:
| 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 |
2 :post_id就是post的id。例如一个post的id是1,那么路由就是/post/1
comments模板会被渲染进post的出口。 所有在comments下的模板(comments/index 和 comments/new)都会被渲染进comments出口。
为了保护路由的命名空间,可以添加深层嵌套的资源:
1 2 3 4 5 6 7 |
App.Router.map(function() {
this.resource('foo', function() {
this.resource('foo.bar', { path: '/bar' }, function() {
this.route('baz'); // This will be foo.bar.baz
});
});
});
|
上面定义的路由器会创建如下路由:
| URL | 路由名称 | 控制器 | 路由 | 模板 |
|---|---|---|---|---|
/ |
index |
App.IndexController |
App.IndexRoute |
index |
/foo |
foo.index |
App.FooIndexController |
App.FooIndexRoute |
foo/index |
/foo/bar |
foo.bar.index |
App.FooBarIndexController |
App.FooBarIndexRoute |
foo/bar/index |
/foo/bar/baz |
foo.bar.baz |
App.FooBarBazController |
App.FooBarBazRoute |
foo/bar/baz |
一些路由在应用创建后便存在:
应用启动时,首先进入App.ApplicationRoute,它将渲染application模板。
App.IndexRoute是默认路由,当用户访问/时,将渲染index模板(除非/被自定义的路由覆盖)。
请记住,这些路由是每个应用的一部分,因此不需要在App.Router.map中指定。
可以定义通配符路由来匹配多个路由。这种方法很有用,比如如果想获取用户进入应用的错误路由的时候。
1 2 3 |
App.Router.map(function() {
this.route('catchall', {path: '/*wildcard'});
});
|
通配符路由与动态路由一样,在使用{{link-to}}或者transitionTo`来进入这个路由的时候,需要提供一个上下文。
1 2 3 4 5 6 7 |
App.ApplicationRoute = Ember.Route.extend({
actions: {
error: function () {
this.transitionTo('catchall', "application-error");
}
}
});
|
在上述代码中,如果一个错误冒泡到应用路由,那么应用将进入catchall路由,并在URL中显示/application-error。