定义路由 编辑页面
英文原文: http://emberjs.com/guides/routing/defining-your-routes/
当启动你的应用时,路由器会负责展示模板,载入数据,以及设置应用状态等任务。 这些都是通过将当前的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
)。
{{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
,
那么你可以在模板里面使用它。
(如果你没有显式的声明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 | posts 1 |
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
。