路由其中一個很重要的職責就是加載適合的model
,初始化數(shù)據(jù),然后在模板上顯示數(shù)據(jù)。
// app/router.js
// ……
Router.map(function() {
this.route('posts');
});
export default Router;
對于posts
這個路由如果要加載名為post
的model
要怎么做呢?代碼實現(xiàn)很簡單,其實在前面的代碼也已經(jīng)寫過了。你只需要重寫model
回調(diào),在回調(diào)中返回獲取到的model
即可。
// app/routes/posts.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
// return Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
// 加載post(是一個model)
return this.store.query('post');
}
});
model
回調(diào)可以返回一個Ember Data記錄,或者返回任何的promise對象(Ember Data也是promise
對象),又或者是返回一個簡單的javascript對象、數(shù)組都可以。但是需要等待數(shù)據(jù)加載完成才會渲染模板,所以如果你是使用Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');
獲取遠程數(shù)據(jù)頁面上會有一段時間是空白的,其實就是在加載數(shù)據(jù),不過這樣的用戶體驗并不好,不過你也不需要擔心這個問題,Ember已經(jīng)提供了解決辦法。還記得上一篇的截圖的路由表嗎?是不是每個路由都有一個xxx_loading
路由,這個路由就是在數(shù)據(jù)加載的時候執(zhí)行的,有關xxx_loading
更多詳細的信息在后面的博文介紹。
一個route
有時候只加載同一個model
,比如路由/photos
就通常是加載模型photo
。如果用戶離開或者是重新進入這個路由模型也不會改變。
然而,有些情況下路由所加載的model
是變化的。比如在一個圖片展示的APP中,路由/photos
會加載一個photo
模型集合并渲染到模板photos
上。當用戶點擊其中一幅圖片的時候路由只加載被點擊的model
數(shù)據(jù),當用戶點擊另外一張圖片的時候加載的又是另外一個model
并且渲染到模板上,而且這兩次加載的model
數(shù)據(jù)是不一樣的。
在這種情形下,訪問的URL就包含了很重要的信息,包括路由和模型。
在Ember應用中可以通過定義動態(tài)段實現(xiàn)加載不同的模型。有關動態(tài)段的知識在前面的Ember.js 入門指南之十三{{link-to}} 助手和Ember.js 入門指南之二十路由定義已經(jīng)做過介紹。
一旦在路由中定義了動態(tài)段Ember就會從URL中提取動態(tài)段的值作為model
回調(diào)的第一個參數(shù)。
// app/router.js
// ……
Router.map(function() {
this.route('posts', function() {
this.route('post', { path: '/:post_id'});
});
});
export default Router;
這段代碼定義了一個動態(tài)段:post_id
,記得動態(tài)段是以:
”開頭。然后在model
回調(diào)中使用動態(tài)段獲取數(shù)據(jù)。
// app/routes/posts.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.findRecord('post', params.post_id);
}
});
可以看到在model
回調(diào)中也是使用在路由中定義的動態(tài)段,并把這個動態(tài)段作為參數(shù)傳遞給Ember的方法findRecord
,Ember會把URL對應位置上的數(shù)據(jù)解析到這個動態(tài)段上。
注意:在model
中的動態(tài)段只在通過URL訪問的時候才會被解析。如果你是通過其他方式(比如使用link-to
進入路由)轉(zhuǎn)入路由的,那么路由中model
回調(diào)方法里的動態(tài)不會被解析,所請求的數(shù)據(jù)會直接從上下文中獲?。憧梢园焉舷挛南胂蟪蒭mber的緩存)。下面的代碼將為你演示這個說法:
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
timestamp: DS.attr('number')
});
定義了3個屬性,id
屬性不需要顯示定義,ember會默認加上。
Router.map(function() {
this.route('posts', function() {
this.route('post', { path: '/:post_id'});
});
});
然后用Ember CLI命令(ember g route posts/post
)在創(chuàng)建路由post
,同時也會自動創(chuàng)建出子模板post.hbs
。創(chuàng)建完成之后會得到如下兩個文件:
1.app/routes/posts/post.js
2.app/templates/posts/post.hbs
修改路由posts.js
,在model
回調(diào)中返回設定的數(shù)據(jù)。
// app/routes/posts.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return [
{
"id":"-JzySrmbivaSSFG6WwOk",
"body" : "testsssss",
"timestamp" : 1443083287846,
"title" : "test"
},
{
"id":"-JzyT-VLEWdF6zY3CefO",
"body" : "33333333",
"timestamp" : 1443083323541,
"title" : "test33333"
},
{
"id":"-JzyUqbJcT0ct14OizMo" ,
"body" : "body.....",
"timestamp" : 1443083808036,
"title" : "title1231232132"
}
];
}
});
修改posts.hbs
,遍歷顯示所有的數(shù)據(jù)。
<ul>
{{#each model as |item|}}
<li>
{{#link-to 'posts.post' item}}{{item.title}}{{/link-to}}
</li>
{{/each}}
</ul>
<hr>
{{outlet}}
修改子路由post.js
,使得子路由根據(jù)動態(tài)段返回匹配的數(shù)據(jù)。
// app/routes/posts/post.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
console.log('params = ' + params.post_id);
return this.store.findRecord('post', params.post_id);
}
});
注意打印信息語句console.log()
;,然后接著修改子模板post.hbs
。
<h2>{{model.title}}</h2>
<p>{{model.body}}</p>
到此,全部所需的測試數(shù)據(jù)和代碼已經(jīng)編寫完畢。下面執(zhí)行http://localhost:4200/posts,可以看到界面上顯示了所有在路由posts的model回調(diào)中設置的測試數(shù)據(jù)。查看頁面的HTML代碼:
可以看到每個連接的動態(tài)段都被解析成了數(shù)據(jù)的id屬性值。 注意:隨便點擊任意一個,注意看瀏覽器控制臺打印的信息。 我點擊了以第一個連接,瀏覽器的URL變?yōu)?/p>
看瀏覽器的控制臺是不是并沒有打印出params = -JzySrmbivaSSFG6WwOk
,在點擊其他的連接結果也是一樣的,瀏覽器控制臺沒有打印出任何信息。
下面我我們直接在瀏覽器地址欄上輸入:http://localhost:4200/posts/-JzyUqbJcT0ct14OizMo然后按enter執(zhí)行,注意看瀏覽器控制臺打印的信息?。?!此時打印了params = -JzyUqbJcT0ct14OizMo
,你可以用同樣的方式執(zhí)行另外兩個鏈接的地址。同樣也會打印出params = xxx
(xxx
為數(shù)據(jù)的id
值)。
我想這個例子應該能很好的解釋了Ember提示用戶需要的注意的問題。
只有直接用過瀏覽器訪問才會執(zhí)行包含了動態(tài)段的model
回調(diào),否則不會執(zhí)行包含有動態(tài)段的回調(diào);如果沒有包含動態(tài)段的model
回調(diào)不管是通過URL訪問還是通過link-to
訪問都會執(zhí)行。你可以在路由posts
的model
回調(diào)中添加一句打印日志的代碼,然后通過點擊首頁上的about
和posts
切換路由,你可以看到控制臺打印出了你在model
回調(diào)中添加的日志信息。
對于在一個mode
l回調(diào)中同時返回多個模型的情況也是時常存在的。對于這種情況你需要在model
回調(diào)中修改返回值為Ember.RSVP.hash
對象類型。比如下面的代碼就是同時返回了兩個模型的數(shù)據(jù):一個是song
,一個是album
。
// app/routes/favorites.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function() {
return Ember.REVP.hash({
songs: this.store.find('song'),
albums: this.store.find('slbum')
});
}
});
然后在模板favorites.hbs
中就可以使用{{#each}}
把兩個數(shù)據(jù)集遍歷出來。遍歷的方式與普通的遍歷方式一樣。
<h2>Song list</h2>
<ul>
{{#each model.songs as |item|}}
<li>{{item.name}}</li>
{{/each}}
</ul>
<hr>
<h2>Album list</h2>
<ul>
{{#each model.albums as |item|}}
<li>{{item.name}}</li>
{{/each}}
</ul>
到此所有路由的model
回調(diào)的情況介紹完畢,model
回調(diào)其實就是把模型綁定到路由上。實現(xiàn)數(shù)據(jù)的初始化,然后把數(shù)據(jù)渲染到模板上顯示。這也是Ember推薦這么做的——就是把操作數(shù)據(jù)相關的處理放在route
而不是放在controller
。
博文完整代碼放在Github(博文經(jīng)過多次修改,博文上的代碼與github代碼可能又出入,不過影響不大!),如果你覺得博文對你有點用,請在github項目上給我點個star
吧。您的肯定對我來說是最大的動力??!
更多建議: