write by yinmingjun,引用請註明。
在看過knockout和angular之後,有些意猶未盡,感覺在web領域內對SPA的探索不應該止步於此,於是開始翻看ember.js架構,希望ember.js能給我帶來驚喜。ember.js在web上的資源較少,官方文檔覆蓋度和深度不夠,很多細節需要到代碼中尋找答案。不過迴歸到ember.js架構本身,這個架構的確帶給我很多驚喜,讓我會有寫文字介紹它的慾望。本文只從架構和概念的角度來解讀ember.js,對於ember.js各個部分的深入研究會寫在後續的文章之中。
在最初看ember的核心概念解釋的時候,看到router這個詞這讓我有些詫異,難道。。。。。。
在進一步瞭解ember之後,證實了我的懷疑:ember確實是通過router作為核心概念來組織其MVC體系架構的。這種方式與目前在伺服器端流行的一些MVC架構(ASP.NET MVC、Django或express等)的處理方式相似,當router的概念出現在面向用戶端的ember之中的時候,我們基本上可以猜測出來,ember已經將頁面間的狀態遷移納入自己的問題領域。
此外,ember詳細的規划了model、view和controller的職責劃分,並支援雙向的資料繫結。
ember的另外一個讓我意外的地方是ember.data。用戶端的js架構很少會涉足實體關聯的領域,筆者曾經在所在的公司開做過類似的JS實體關聯映射體系,深知其複雜度和價值。ember將實體的定義和實體關聯納入其問題領域,是眾多JS開發人員的福音,ember.data有助於我們從資料管理的細節中解放出來。不過ember.data不是本文的重點,後面筆者會寫專文來介紹它,本文只是簡單的介紹其在ember.js體系中的角色。
在讀到這裡的時候,大家會不會有這樣的感覺:ember會不會太重了。ember的js尺寸(v1.0.0版本)壓縮過的有200K,未壓縮過的有800K,的確驚人,還不包括ember.data(v0.13版本,250K,70K尺寸)和handlebar的js尺寸。這些訊息可以給我們一些啟示,ember是面向未來的、重型的web應用支撐架構,使用的時候需要良好的設計和規劃,如果不清楚這個定位也許會導致ember使用上的失敗經曆,這點請大家明白。
接下來進入正題,我們會逐步介紹ember裡面的核心概念,瞭解ember的應用程式的架構。
一、從DEMO開始
下面是來自ember官網的一個DEMO,我們看一下代碼。
HTML:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ember Starter Kit</title>
<link rel="stylesheet" href="css/normalize.css">
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<script type="text/x-handlebars">
<h2>Welcome to Ember.js</h2>
{{outlet}}
</script>
<script type="text/x-handlebars" data-template-name="index">
<ul> {{#each item in model}}
<li>{{item}}</li>
{{/each}}
</ul>
</script>
<script src="js/libs/jquery-1.9.1.js"></script>
<script src="js/libs/handlebars-1.0.0-rc.4.js"></script>
<script src="js/libs/ember-1.0.0-rc.5.js"></script>
<script src="js/app.js"></script>
</body>
</html>
app.js:
App = Ember.Application.create();
App.Router.map( function() {
// put your routes here
});
App.IndexRoute = Ember.Route.extend({
model: function() {
return ['red', 'yellow', 'blue'];
}
});
例子很簡單,只是建立一個ember的appliation,然後將model中的資料依次的綁定到li之中。不過應用架構的角度來看,這個例子覆蓋了ember中的主要的功能。需要注意,script標記的類型是text/x-handlebars。Ember在載入頁面時,會抓取這些內容。
在這個例子中,我們基本上可以看到ember應用架構模式的主要脈絡。
1、預設的'/'到App.IndexRoute的映射
省略的等效代碼:
App.Router.map( function() { this.resource( 'index', { path: '/' } ); });
2、預設的建立IndexRoute的controller
省略的代碼:
App.IndexRoute = Ember.Route.extend({
setupController: function(controller) {
controller.set('content', ['red', 'yellow', 'blue']);
}
});
3、預設的application template
省略了applicaion的template名稱:
<script type="text/x-handlebars" data-template-name="application">
<h1>Application Template</h1>
{{outlet}}
</script>
4、App.IndexRoute對名字為'index'的template的引用
5、程式啟動後對{{outlet}}和'index'的template的綁定
這種name mapping的方式可以大幅度減少配置的工作量,在現代的MVC體系中廣泛採用,ember也引入了這種處理方式。後面我們會詳細的闡述ember的name mapping的方式。
實際上,如果最簡單的建立一個ember應用,僅需要一行代碼:
App = Ember.Application.create({});
而ember會在後面預設的加上下面的代碼:
// Create the application namespace
App = Ember.Application.create({});
// Create the global router to manage page state via URLs
App.Router.map( function() {});
// Create the default application route to set application-level state properties
App.ApplicationRoute = Ember.Route.extend({});
// Create the default application template
<script type="text/x-handlebars" data-template-name="application">
{{outlet}}
</script>
從這個demo中,我們能看到Application,Router,Template,Controller,Model等概念,這些概念我們會在下一節簡單的闡述。
二、ember的基本概念
為了容易理解,這幾個概念會儘可能簡單的描述,盡量不引入複雜的因素。
1、application的概念
在ember中,建立applicaion非常的簡單,只需要一行代碼:
window.App = Ember.Application.create();
App的變數名字是什麼都可以,建立後的app中可以作為應用層級狀態和資料的載體。例如,建立了一個App中的view,可以這麼寫:
App.MyView = Ember.View.extend();