EmberJS 用了一系列的命名约定,使得各个对象(application,router,model,template...)联系起来。好处是,避免写烦人的简单代码。
下面的说明 都基于:我们的应用取名 App,
THE APPLICATION
在应用启动后,Ember自动找App的三个内容:
1. App.ApplicationRoute (路由,为了获得数据 )
2.App.ApplicationController ( 控制器)
3. application 的模板
如果找到名称是application的模板,把 ApplicationController 的实例(单例) 与模板绑定,模板可以通过controller属性访问ApplicationController 。
如果找到了ApplicationRoute ,那么,在展示模板前,会先执行ApplicationRoute 中的一些钩子, 钩子可以看成一个拦截器,对一个Route对象,定义的钩子有model, setupController. 下面是个例子:
App.ApplicationRoute = Ember.Route.extend({ setupController: function(controller) { // `controller` is the instance of ApplicationController controller.set('title', "Hello world!"); } }); App.ApplicationController = Ember.Controller.extend({ appName: 'My First Example' });
<!-- application template --> <h1>{{appName}}</h1> <h2>{{title}}</h2>
SIMPLE ROUTES
对于每一个路由,Ember认为都会有一个控制器,以及相同名字的模板。例如,下例定义了一个路由 favorites
App.Router.map(function() { this.route('favorites'); });
对应 favorites 这个路由,Ember将查找以下三个内容
1.App.FavoritesRoute
2. App.FavaritesController
3. 名称叫 favorites 的模板
Ember 会把 favorites的内容填到application模板中的{{outlet}}中,并把FavoritesController的实例作为模板的controller属性。
如果给出了 FavoritesRoute, 在渲染模板前,先实例化FavoritesRoute(用来准备数据)
App.FavoritesRoute = Ember.Route.extend({ model: function() { // the model is an Array of all of the posts return this.store.find('post'); } });
在上面的例子中,没有指定FavoritesController, 但 Ember 判断到 model 是一个数组,所以会把 ArrayController 与模板绑定,在模板中可以这样写
<ul> {{#each controller}} <li>{{title}}</li> {{/each}} </ul>
DYNAMIC SEGMENTS(route)
动态的段(路由),对应带参数的URL,比如
App.Router.map(function() { this.resource('post', { path: '/posts/:post_id' }); });
与简单路由一样,Ember也同样会寻找 App.PostRoute, App.PostController ,post模板。
App.PostRouter 例子:
App.PostRoute = Ember.Route.extend({ model: function(params) { return this.store.find('post', params.post_id); }, serialize: function(post) { return { post_id: post.get('id') }; } });
model方法根据post_id找到数据。serialize 方法提供了参数,该参数在model转成URL中用到。
如果在动态段中是以_id 为结尾,model钩子会把参数前部分(post) 作为类名称,也就是认为有一个类叫App.Post, 返回的实例的类就是App.Post.
ROUTE, CONTROLLER AND TEMPLATE DEFAULTS
如果一个Route 没有指定Controller,Ember依然会根据Route 返回的Model类型创建Controller.
1. 如果model是数组,创建ArrayController
2.如果mode是对象,创建ObjectController
如果没有对应的模板,会啥也不做。
NESTING(层级路由)
App.Router.map(function() { this.resource('posts', function() { // the `posts` route this.route('favorites'); // the `posts.favorites` route this.resource('post'); // the `post` route }); });
上例定义了posts 下还有 post.favorites, posts.post 两个子路由,对于子路由,Ember依旧会找Controller,Route,及模板,比如:
posts |
PostsController |
PostsRoute |
posts |
posts.favorites |
PostsFavoritesController |
PostsFavoritesRoute |
posts/favorites |
post |
PostController |
PostRoute |
post |
THE INDEX ROUTE
每一级路由(包括顶层),Ember都会产生一个叫index 的路由,比如:
App.Router.map(function() { this.route('favorites'); });
等同于:
App.Router.map(function() { this.route('index', { path: '/' }); this.route('favorites'); });
如果访问 / ,Ember就会找
App.IndexRoute, AppIndexControll, index的模板。index模板会渲染到application 模板的{{outlet}}中
进一步的例子:
App.Router.map(function() { this.resource('posts', function() { this.route('favorites'); }); });
等同于
App.Router.map(function() { this.route('index', { path: '/' }); this.resource('posts', function() { this.route('index', { path: '/' }); this.route('favorites'); }); });
如果访问 /posts, 那么当前的路由就是posts.index, Ember 模板 App.PostIndexRoute,App.PostIndexController,以及 posts/index 模板。posts模板会渲染到application 模板的{{outlet}}中,而posts/index模板会渲染到post模板的{{outlet}}中.
如果该部/posts/favorites ,post/favarites模板会渲染到 post 模板的{{outlet}}中。
总结:
1. 每个应用应该有 controller,route,application模板
2. 每个路由,也应用相应的 controller,route,application。