Ember 指定與路由關(guān)聯(lián)的模型

2018-01-06 17:47 更新

路由其中一個(gè)很重要的職責(zé)就是加載適合的model,初始化數(shù)據(jù),然后在模板上顯示數(shù)據(jù)。

1,普通model關(guān)聯(lián)

//  app/router.js


//  ……


Router.map(function() {
    this.route('posts');
});


export default Router;

對(duì)于posts這個(gè)路由如果要加載名為postmodel要怎么做呢?代碼實(shí)現(xiàn)很簡(jiǎn)單,其實(shí)在前面的代碼也已經(jīng)寫(xiě)過(guò)了。你只需要重寫(xiě)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(是一個(gè)model)
        return this.store.query('post');
    }
});

model回調(diào)可以返回一個(gè)Ember Data記錄,或者返回任何的promise對(duì)象(Ember Data也是promise對(duì)象),又或者是返回一個(gè)簡(jiǎn)單的javascript對(duì)象、數(shù)組都可以。但是需要等待數(shù)據(jù)加載完成才會(huì)渲染模板,所以如果你是使用Ember.$.getJSON('https://api.github.com/repos/emberjs/ember.js/pulls');獲取遠(yuǎn)程數(shù)據(jù)頁(yè)面上會(huì)有一段時(shí)間是空白的,其實(shí)就是在加載數(shù)據(jù),不過(guò)這樣的用戶(hù)體驗(yàn)并不好,不過(guò)你也不需要擔(dān)心這個(gè)問(wèn)題,Ember已經(jīng)提供了解決辦法。還記得上一篇的截圖的路由表嗎?是不是每個(gè)路由都有一個(gè)xxx_loading路由,這個(gè)路由就是在數(shù)據(jù)加載的時(shí)候執(zhí)行的,有關(guān)xxx_loading更多詳細(xì)的信息在后面的博文介紹。

2,動(dòng)態(tài)model

一個(gè)route有時(shí)候只加載同一個(gè)model,比如路由/photos就通常是加載模型photo。如果用戶(hù)離開(kāi)或者是重新進(jìn)入這個(gè)路由模型也不會(huì)改變。 然而,有些情況下路由所加載的model是變化的。比如在一個(gè)圖片展示的APP中,路由/photos會(huì)加載一個(gè)photo模型集合并渲染到模板photos上。當(dāng)用戶(hù)點(diǎn)擊其中一幅圖片的時(shí)候路由只加載被點(diǎn)擊的model數(shù)據(jù),當(dāng)用戶(hù)點(diǎn)擊另外一張圖片的時(shí)候加載的又是另外一個(gè)model并且渲染到模板上,而且這兩次加載的model數(shù)據(jù)是不一樣的。

在這種情形下,訪問(wèn)的URL就包含了很重要的信息,包括路由和模型。

在Ember應(yīng)用中可以通過(guò)定義動(dòng)態(tài)段實(shí)現(xiàn)加載不同的模型。有關(guān)動(dòng)態(tài)段的知識(shí)在前面的Ember.js 入門(mén)指南之十三{{link-to}} 助手Ember.js 入門(mén)指南之二十路由定義已經(jīng)做過(guò)介紹。

一旦在路由中定義了動(dòng)態(tài)段Ember就會(huì)從URL中提取動(dòng)態(tài)段的值作為model回調(diào)的第一個(gè)參數(shù)。

//  app/router.js
// ……


Router.map(function() {
    this.route('posts', function() {
        this.route('post', { path: '/:post_id'});
    }); 
});


export default Router;

這段代碼定義了一個(gè)動(dòng)態(tài)段:post_id,記得動(dòng)態(tài)段是以:”開(kāi)頭。然后在model回調(diào)中使用動(dòng)態(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)中也是使用在路由中定義的動(dòng)態(tài)段,并把這個(gè)動(dòng)態(tài)段作為參數(shù)傳遞給Ember的方法findRecord,Ember會(huì)把URL對(duì)應(yīng)位置上的數(shù)據(jù)解析到這個(gè)動(dòng)態(tài)段上。

注意:在model中的動(dòng)態(tài)段只在通過(guò)URL訪問(wèn)的時(shí)候才會(huì)被解析。如果你是通過(guò)其他方式(比如使用link-to進(jìn)入路由)轉(zhuǎn)入路由的,那么路由中model回調(diào)方法里的動(dòng)態(tài)不會(huì)被解析,所請(qǐng)求的數(shù)據(jù)會(huì)直接從上下文中獲取(你可以把上下文想象成ember的緩存)。下面的代碼將為你演示這個(gè)說(shuō)法:

1,首先創(chuàng)建一個(gè)model:ember g model post

import DS from 'ember-data';


export default DS.Model.extend({
    title: DS.attr('string'),
    body: DS.attr('string'),
    timestamp: DS.attr('number')
});

定義了3個(gè)屬性,id屬性不需要顯示定義,ember會(huì)默認(rèn)加上。

2,在posts下增加一個(gè)子路由

Router.map(function() {
    this.route('posts', function() {
        this.route('post', { path: '/:post_id'});
    }); 
});

然后用Ember CLI命令(ember g route posts/post)在創(chuàng)建路由post,同時(shí)也會(huì)自動(dòng)創(chuàng)建出子模板post.hbs。創(chuàng)建完成之后會(huì)得到如下兩個(gè)文件:

1.app/routes/posts/post.js
2.app/templates/posts/post.hbs

修改路由posts.js,在model回調(diào)中返回設(shè)定的數(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ù)動(dòng)態(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);
    }
});

注意打印信息語(yǔ)句console.log();,然后接著修改子模板post.hbs。





<h2>{{model.title}}</h2>
<p>{{model.body}}</p>

到此,全部所需的測(cè)試數(shù)據(jù)和代碼已經(jīng)編寫(xiě)完畢。下面執(zhí)行http://localhost:4200/posts,可以看到界面上顯示了所有在路由posts的model回調(diào)中設(shè)置的測(cè)試數(shù)據(jù)。查看頁(yè)面的HTML代碼:

html

可以看到每個(gè)連接的動(dòng)態(tài)段都被解析成了數(shù)據(jù)的id屬性值。 注意:隨便點(diǎn)擊任意一個(gè),注意看瀏覽器控制臺(tái)打印的信息。 我點(diǎn)擊了以第一個(gè)連接,瀏覽器的URL變?yōu)?/p>

html

看瀏覽器的控制臺(tái)是不是并沒(méi)有打印出params = -JzySrmbivaSSFG6WwOk,在點(diǎn)擊其他的連接結(jié)果也是一樣的,瀏覽器控制臺(tái)沒(méi)有打印出任何信息。

下面我我們直接在瀏覽器地址欄上輸入:http://localhost:4200/posts/-JzyUqbJcT0ct14OizMo然后按enter執(zhí)行,注意看瀏覽器控制臺(tái)打印的信息?。?!此時(shí)打印了params = -JzyUqbJcT0ct14OizMo,你可以用同樣的方式執(zhí)行另外兩個(gè)鏈接的地址。同樣也會(huì)打印出params = xxxxxx為數(shù)據(jù)的id值)。

我想這個(gè)例子應(yīng)該能很好的解釋了Ember提示用戶(hù)需要的注意的問(wèn)題。 只有直接用過(guò)瀏覽器訪問(wèn)才會(huì)執(zhí)行包含了動(dòng)態(tài)段的model回調(diào),否則不會(huì)執(zhí)行包含有動(dòng)態(tài)段的回調(diào);如果沒(méi)有包含動(dòng)態(tài)段的model回調(diào)不管是通過(guò)URL訪問(wèn)還是通過(guò)link-to訪問(wèn)都會(huì)執(zhí)行。你可以在路由postsmodel回調(diào)中添加一句打印日志的代碼,然后通過(guò)點(diǎn)擊首頁(yè)上的aboutposts切換路由,你可以看到控制臺(tái)打印出了你在model回調(diào)中添加的日志信息。

3,多模型

對(duì)于在一個(gè)model回調(diào)中同時(shí)返回多個(gè)模型的情況也是時(shí)常存在的。對(duì)于這種情況你需要在model回調(diào)中修改返回值為Ember.RSVP.hash對(duì)象類(lèi)型。比如下面的代碼就是同時(shí)返回了兩個(gè)模型的數(shù)據(jù):一個(gè)是song,一個(gè)是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}}把兩個(gè)數(shù)據(jù)集遍歷出來(lái)。遍歷的方式與普通的遍歷方式一樣。





<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)其實(shí)就是把模型綁定到路由上。實(shí)現(xiàn)數(shù)據(jù)的初始化,然后把數(shù)據(jù)渲染到模板上顯示。這也是Ember推薦這么做的——就是把操作數(shù)據(jù)相關(guān)的處理放在route而不是放在controller。
博文完整代碼放在Github(博文經(jīng)過(guò)多次修改,博文上的代碼與github代碼可能又出入,不過(guò)影響不大?。绻阌X(jué)得博文對(duì)你有點(diǎn)用,請(qǐng)?jiān)趃ithub項(xiàng)目上給我點(diǎn)個(gè)star吧。您的肯定對(duì)我來(lái)說(shuō)是最大的動(dòng)力??!

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)