建立一個Hybird App應用框架 Ember.js + jQuery Mobile + PhoneGap

必備知識

  1. HTML + JavaScript + CSS的語法掌握。
  2. jQuery的語法掌握。
  3. 基於Eclipse的PhoneGap環境配置。
  4. Ember.js的簡單瞭解。
  5. Handlerbars.js的簡單瞭解。
  6.  

環境搭建

  1. Windows 7
  2. Eclipse + Android SDK

用戶級別

所有javascript

範例文件

隨着HTML 5的興起,基於此的項目也愈來愈的多,於是出現了不少MVC框架,如:Backbone.js、Ember.js、Angular.js等,此係列將闡述這些框架在代碼層面的區別,但願能夠給初學者一些思路。css

本文將介紹Ember.js構建基於jQuery Mobile的PhoneGap項目(Hybird App)。html

功能介紹

使用Ember.js + jQuery Mobile + PhoneGap構建一個Hybird App項目,命名爲Adobe Reader,具備以下功能:html5

  1. 讀取http://feeds.adobe.com/xml/rss.cfm的數據(XML源)。
  2. 將XML的內容以列表的形式展現出來。
  3. 點擊任意列表項目(Item),能夠跳轉到相應地址。

項目依賴

  1. jQuery(1.8.2版)
  2. jQuery Mobile(1.2.0 Final版)
  3. Ember.js(0.9.8.1版)
  4. Ember-bridge-jqm(0.1)
    • 下載地址:https://github.com/kenshin/ember-bridge-jqm
    • Ember.js沒法直接與jQuery Mobile搭配,因此須要ember-bridge-jqm來「代理」。
    • 代碼基於https://github.com/LuisSala/emberjs-jqm和https://github.com/tolbard/ember-moving修改。
  5. xml2json
    • 下載地址:請看範例文件
    • XML轉JSON的jQuery插件。
  6. PhoneGap(2.0.0 版)

範例文件

  1. 附件

經過本文將學會

  1. 理解Ember.js的MVC結構特色。
  2. 掌握Ember.js與jQuery Mobile的特殊寫法(ember-bridge-jqm的運用)
  3. 掌握Ember.js的特點功能:UI Binding。

項目截圖

Figure1

工程結構

Figure2
  1. common:共同的JS類庫,如jQuery、jQuery Plugin等。
  2. ember:Ember.js相關類庫。
  3. javascripts:Ember.js對應MVC結構的JavaScript代碼。
  4. jqm:jQuery Mobile相關類庫。
  5. phonegap:PhoneGap相關類庫。
  6. stylesheets:CSS文件。

項目架構

Figure3

代碼分析

下面將展現Adobe Reader的關鍵代碼,並分別介紹Ember.js中M(Model)V(View)C(Controller)代碼特色、UI Binding的實現等功能。java

Application(應用程序入口)

App = Em.Application.create();jquery

與全部的Ember.js App都是同樣,首先要創建一個Applicationgit

Views(視圖)

App.PageView = Mov.PageView.extend();github

上面的代碼與一般的Ember.js App在View(視圖)層的繼承不太同樣,主要區別在於所有的View(視圖)都繼承自Mov,那麼Mov是什麼?ajax

Mov定義在ember-bridge-jqm中,能夠在assets\www\ember\ember-bridge-jqm.js中找到。爲何Ember.js不能直接與jQuery Mobile一塊兒使用,而非要一個「代理」才行?json

由於Ember.js在實現的時候會修改HTML代碼,所以具備「侵入性」。衆所周知jQuery Mobile也是一個「侵入性」很強的類庫,例如:它會把 <div data-role="header"></div>這樣的代碼「改成」<div data-role="header" class="ui-header ui-bar-a" role="banner"></div>。當這兩種「侵入性」的類庫放在一塊兒,就會出現各類未知錯誤,因此纔有ember-bridge-jqm.js這樣的「代理」類庫。

一般一個典型的jQuery Mobile具備以下結構:

<div data-role="page"> <div data-role="header"></div> <div data-role="content"></div> <div data-role="footer"></div> </div>

加入ember-bridge-jqm.js後,HTML結構能夠直接用JavaScript的方式實現:

App.PageView = Mov.PageView.extend(); App.HeaderView = Mov.HeaderView.extend(); App.FooterView = Mov.FooterView.extend(); App.ContentView = Mov.ContentView.extend();

注:上述代碼分別實現了jQuery Mobile的 "page" "header" "content" "footer"視圖。

以上就是View(視圖)層的關鍵代碼,主要負責實現jQuery Mobile的結構,接下來看一下Model(模型)的代碼。

Model(模型)

定義以下數據結構(value Object)

App.Articles = Ember.Object.extend({ title : null, link : null, desc : null, creator : null, date : null });

上述結構與RSS源的XML節點保持一致。因爲須要處理XML,所以增長一個叫作ServicesModel的函數,功能是讀取XML,代碼以下:

App.ServicesModel = function( target, url ) { $.ajax({ type : "GET", url : url, success: function( xml ) { //get json var json = $.xml2json( xml ); //call json2obj App.Json2Obj( target, json.item ); } }); }

ServicesModel具備以下功能:

  1. 使用Ajax方式讀取RSS源。
  2. 將讀取的XML轉化爲JSON對象。
  3. 調用App.Json2Obj。

再看一下Json2Obj的實現:

App.Json2Obj = function( target, tmp ) { target.set( 'content', [] ); $( tmp ).each( function( index, value ) { var tmp = App.Articles.create({ title : value.title, link : value.link, desc : value.description, creator : value.creator, date : value.date, }); target.pushObject( tmp ); }); }

Json2Obj具備以下功能:

  1. 循環遍歷傳入的JSON對象,並將遍歷後的內容保存到VO(App.Articles.create())
  2. 經過pushObject將每一個遍歷後的App.Articles(VO)保存到target(傳入的參數)。

注:pushObject是Ember.js方法,與Ember.ArrayController一同使用,將循環遍歷(each)後的VOApp.Articles)保存到(pushObjectArrayControllercontent中。

以上就是Model(模型)層的關鍵代碼,主要負責實現XML的讀取、解析和保存,接下來看一下Controller(控制器)的代碼。

Controller(控制器)

 

App.getArticlesController = Ember.ArrayController.create({ content : [], init : function () { //call services model App.ServicesModel( this, "http://feeds.adobe.com/xml/rss.cfm?query=byMostRecent&languages=5" ); } });

getArticlesController具備以下功能:

  1. 實現Ember.js的控制器App.getArticlesController = Ember.ArrayController.create();
  2. 調用Model層的ServicesModel,並傳入兩個參數:
    • this(供使用pushObject方法)
    • URL(傳入解析用的RSS地址)

總結

以上就是JavaScript端MVC各層的關鍵代碼,代碼的實現與其餘框架並沒有太大的區別,須要注意的是如何使用Ember.js方式實現MVC結構的寫法:

  1. Model:Ember.Object.extend();
  2. View:Mov.PageView.extend();
  3. Controller:Ember.ArrayController.create();

接下來看一下HTML端的Ember.js寫法,並展現Ember.js有別於其餘MVC框架的特色:UI Binding

HTML端相關類庫的引入

<head>標籤內:

<!-- jquery mobile --> <link rel="stylesheet" href="jqm/jquery.mobile-1.2.0.min.css" /> <!-- customer --> <link rel="stylesheet" href="stylesheets/style.css" />

<body>標籤內:

<!-- common --> <script src="common/jquery-1.8.2.min.js"></script> <script src="common/jquery.xml2json.js"></script> <!-- jquery mobile --> <script src="jqm/jquery.mobile-1.2.0.min.js"></script> <!-- ember.js --> <script src="ember/ember-0.9.8.1.min.js"></script> <script src="ember/ember-bridge-jqm.js"></script> <!-- customer --> <script src="javascripts/app.js"></script> <!-- phonegap --> <script src="phonegap/cordova-2.0.0.js"></script>

注:之因此要把<script>放到<body>標籤中主要基於加快加載速度的考慮。

jQuery Mobile結構的實現(ember-bridge-jqm的運用)

<body>中加入以下代碼:

<script type="text/x-handlebars" data-template-name="main"></script> <div data-role="page"></div>

注:data-template-name的值必定要設定爲"main"

在javascripts/app.js的View(視圖)層中加入以下代碼:

App.PageView = Mov.PageView.extend({ templateName:'main', id: 'page-view', didInsertElement: function() { $.mobile.changePage(this.$()); } });

注:App.PageView.templateNameid的值必定按照上述設定。

在HTML端加入以下代碼:

{{#view App.HeaderView}} ..... {{/view}} {{#view App.ContentView}} ..... {{/view}} {{#view App.FooterView}} ..... {{/view}}

這些代碼的結構等價於jQuery Mobile的結構:

<div data-role="header"></div> <div data-role="content"></div> <div data-role="footer"></div>

注:App.HeaderViewApp.ContentViewApp.FooterView定義在javascripts/app.js中,{{}}是模版引擎(Handlebars.js)的語法。

Listview(UI Binding)的實現

在javascripts/app.js新增一個View(視圖)層,命名爲ListView

App.ListView = Mov.ListView.extend();

在HTML端加入以下代碼:(重點)

{{#view App.ContentView}} {{#collection App.ListView contentBinding="App.getArticlesController"}} <a {{ bindAttr href="content.link" }} data-ajax="false" > <h3>{{ content.title }}</h3> <p>via {{ content.creator }}</p> <p>{{{ content.desc }}}</p> </a> {{/collection}} {{/view}}

具備以下功能:

  1. 定義了一個ContentView,並在其中加入ListView
  2. ListViewcontentBinding設定爲App.getArticlesController,因爲ListView是一個數組結構(App.getArticlesController = Ember.ArrayController.create();)因此使用了關鍵字Collection,而非View。
  3. content.title、content.creator、content.desc來源於App.getArticlesController.content,而App.getArticlesController.content的值是調用pushObject而來,經過App.Json2Obj的代碼可知,content.title、content.creator、content.desc分別存儲瞭解析XML後的App.Articles(Value Object)值。

注:bindAttr href="content.link"並無寫成:<a href="{{ content.link }}">,是由於Ember.js在「注入」代碼的時候,會生成<script id="metamorph-0-start" type="text/x-placeholder">XXX</script>這樣的結構,因此在設定href時不能直接寫{{ content.link }},而是使用bindAttr方式。

總結

Embe.js經過CollectionpushObject以及模版引擎(Handlebars.js)來實現。

PhoneGap

因爲PhoneGap只起到打包(Android App)做用,並無使用PhoneGap的相關功能,所以無需引入<script src="phonegap/cordova-2.0.0.js"></script>,直接打包便可,PhoneGap的過程略去。

結論

  1. Ember.js與jQuery Mobile都是具備「侵入性」的框架,因此儘可能不要放在一塊兒使用,如在一塊兒使用,須要「代理」方式(ember-bridge-jqm)。
  2. 因爲Ember.js與jQuery Mobile的「不兼容性」,因此在編寫jQuery Mobile組件的時候,沒法直接寫到HTML中,而是寫到Handlebars.js的模版裏面。(針對動態生成組件而言)
  3. Ember.js搭配的UI庫儘可能不具備「侵入性」,例如:Bootstrap等。
  4. Ember.js最強大的地方(之一)在於UI Binding。(經過CollectionpushObject以及模版引擎(Handlebars.js)實現)
  5. 若是你對Cocoa熟悉的話,你會在Ember.js身上找到它的身影。
  6. 若是你對Flex熟悉的話,你會找到久違的「dataProvide」和「itemrender」屬性。

 

引用地址:http://www.adobe.com/cn/devnet/html5/articles/ember-jquery-phonegap.html

相關文章
相關標籤/搜索