JavaScript MV* 框架剖析
快速學習 JavaScript MV* 框架的關鍵是將它們分解為一系列功能。 MV* 應用程序的主要功能是路由、數據綁定、模板/視圖、模型和數據訪問。在這篇文章中,我將描述這些特性,並展示來自 AngularJS、Backbone 和 Ember 的每個特性的代碼示例。您將開始具體了解這些框架試圖幫助您完成什麼,並意識到它們的相似之處多於不同之處。事實上,很明顯大多數框架都大量借鑒了其他框架的成功經驗。
不要太在意理解每一行代碼。現在,請嘗試了解它們的相似之處以及它們可以為您的項目解決的問題。
路由
路由,至少將你的 URL 映射到一個函數,但有時甚至會實現一個完整的“狀態機”設計模式來管理視圖中的狀態轉換。如果您曾經在 Rails、CodeIgniter、CakePHP、ASP.NET MVC 等服務器端 MVC 框架中使用過路由器,那麼您可以將 JavaScript MV* 路由器視為相同的東西,但運行在JavaScript 中的客戶端。
您可能想知道這是如何工作的,以及它是否適用於舊版瀏覽器? URL 中哈希標記之後的所有內容都考慮了路由,但是,如果配置了 HTML 推送狀態支持(在大多數框架中使用一行代碼),那麼與路由匹配的沒有哈希的 URL 將在客戶端上被攔截並運行 JavaScript也是。
足夠的細節讓我們看一些代碼。
主幹示例
這是Backbone.js中路由的一個簡單示例:
注意 AppRouter
目的。路由映射到函數。這些函數只是創建一個視圖對象,該對像管理一個 DOM 片段並在 URL 更改時將其添加到頁面中。 Backbone.history.start()
告訴 Backbone 開始監聽 URL 變化。
AngularJS 示例
下面是 AngularJS 中路由的一個簡單示例:
AngularJS 示例與 Backbone 示例非常相似,除了路由映射到 templateUrl
s 和控制器功能。
Ember 示例
下面是一個簡單的 Ember 路由示例:
同樣,與其他非常相似,除了 Ember.js 路由器的“資源”對象的第一個參數是 routeName
第二個是 URL。這些參數的順序起初讓我感到困惑,直到有人指出 path 參數是可選的,並且經常可以按照約定設置,就像示例中的 about 頁面一樣。此外,需要 Ember 模板才能使這個簡單的路由示例工作,但我將在後面的部分中介紹它們。現在知道模板放在 {{outlet}}
中就足夠了 .
數據綁定
數據綁定允許在視圖中更新模型數據中的更改和/或在模型中自動更新視圖中的更改,而無需額外的代碼。單向數據綁定通常表示對模型的更改會傳播到視圖。雙向數據綁定增加了視圖更改立即顯示在模型上的能力。數據綁定消除了開發人員編寫的大量樣板代碼,讓開發人員能夠專注於應用程序中的獨特問題。
AngularJS 示例
下面是 AngularJS 中雙向數據綁定的簡單示例。在輸入字段中鍵入將在歡迎消息後顯示輸入的文本。
主幹示例
Backbone 沒有自動數據綁定,但可以手動進行。在實踐中,我發現單向數據綁定在模型發生更改時更新視圖非常有用。從視圖到模型的數據綁定在實際用例中並不常見。
下面是一個簡單的例子,代碼已經實現了雙向綁定。
總之,您監聽模型上的更改事件並調用視圖的渲染屬性來讓模型更新視圖。同樣,您監聽 keyup
在輸入上並通過使用 jQuery 從輸入中獲取值並將其設置在模型上以使視圖更新模型來更改模型。這個示例應該讓您了解需要多少代碼才能使數據綁定正常工作。還值得注意的是,有許多插件添加了對 Backbone 數據綁定的支持。
Ember 示例
Ember 中的數據綁定如下所示:
Ember 使用熟悉的 Handlebars 進行模板化,但該框架還包括“輸入助手”來綁定常見的表單輸入字段。花括號 {{
替換尖括號 <
在本例中的輸入和 name
屬性沒有引號,所以助手知道綁定它。
模板/視圖
模板可以是整個 HTML 頁面,但更常見的是較小的 HTML 片段,其中包含用於動態數據的數據綁定佔位符表達式。它們可以是無邏輯的,其理念是您的視圖中應該幾乎沒有邏輯,而其他的則允許您將 JavaScript 直接嵌入到模板中。模板可以是基於 DOM 的,並使用 DOM 動態插入動態數據或基於字符串,將 HTML 視為字符串並替換動態部分。
讓我們看一些例子。
AngularJS 示例
這是 AngularJS 中的一個簡單模板示例。
您會注意到這與前面的路由示例非常相似,添加了一些數據綁定以顯示模板如何幫助您的應用程序。模板都包含在 script
中 主 HTML 文件中的標籤,以使示例易於遵循並在 jsfiddle.net 中工作,但模板可以通過為 templateUrl
提供有效的文件路徑在 AngularJS 中的視圖外部 配置$routeProvider
時的屬性 .
在關注性能的大型應用程序中處理模板的首選方法是在 Angular $templateCache
中連接和註冊 AngularJS 模板 在編譯時使用諸如此類的構建任務。
Ember 示例
下面是 Ember 中的模板示例。
Ember 路由是一個對象,它告訴模板它應該顯示哪個模型。我認為它是您的模板和資源 (URL) 的最基本控制器,其主要工作是加載模型。如果您需要花哨並存儲應用程序狀態,那麼您需要一個控制器。
主幹示例
現在,讓我們看一個 Backbone 中模板的簡單示例。
這是對路由示例的修改,但 HTML 不是硬編碼在視圖對象的模板屬性中,而是標記現在位於 HTML 頁面中的 script
中 帶有 id
的標籤 屬性(瀏覽器會忽略它們無法識別的類型的腳本標籤,例如文本/模板,因此不會顯示或執行模板)。要獲取模板(HTML 片段),我們使用 jQuery 選擇器通過 script
查找元素 標籤的id
,抓住innerHTML
,然後將 HTML 分配給視圖對象的模板屬性(它只是一個字符串)。
型號
模型是通常稱為業務對象、域對像或實體的客戶端版本。一般來說,客戶端 MV* 框架中的模型背後的想法是為應用程序中的數據以及應該用該數據封裝的任何行為建立一個中心點。該模型可以與模型數據通常存儲在 DOM 中的服務器端 MVC 和 jQuery 架構進行對比。通過擁有一個模型,目標是從 DOM 中移除該數據和狀態,並將其放在一個可以重複使用的公共位置。
主幹示例
模型保存數據並將其排除在 DOM 之外,並發出諸如 change
之類的事件 它允許眾多視圖做出相應的反應,並在需要的任何地方更新用戶界面。這為您提供了一個事實來源,而不是用戶界面。
我已經修改了之前的數據綁定示例,添加了一個新模板和查看相同 Person 模型對象的視圖。以前,為了簡單起見,我動態聲明了 Person 模型,但現在我添加了對 Backbone.Model.extend()
的調用 演示如何為模型創建原型,該模型可以像經典語言中的類一樣反複使用。注意兩個視圖如何監聽同一個人物模型對象(更改事件)並更新自己。通過擁有這個單一數據源,對特定 DOM 元素的大量調用可以封裝在它們自己的整潔視圖中,並且一個模型可以為它們提供全部服務。
AngularJS 示例
AngularJS 中存在一個模型,即關於應用程序狀態的真相,但 Angular 允許您使用普通的舊 JavaScript 對像作為模型,然後“在後台”將觀察者添加到視圖中數據綁定的任何屬性使用指令 ng-model
.然後,這些觀察者會自動提醒綁定到同一模型的應用程序的其他部分,並且這些 DOM 元素知道如何更新自己。
這是更新後的 AngularJS 數據綁定示例,顯示了正在更新的視圖的兩個部分。
數據訪問
數據訪問是關於如何獲取和保存應用程序的數據。通常,這些框架假定您正在調用返回 JSON 的 API。
AngularJS 示例
AngularJS 以兩種不同的方式處理數據。首先,通過以與 jQuery 的 $.ajax
非常相似的方式提供對手動 Ajax 調用的支持 通過 $http
實現的功能 .另外,如果你的後端是一個嚴格的 RESTful 服務,AngularJS 提供了一個 $resource
調用 RESTful 服務的類非常簡潔。
$http
示例
app.factory('myService', function($http) {
return {
getFooOldSchool: function(callback) {
$http.get('foo.json').success(callback);
}
};
});
app.controller('MainCtrl', function($scope, myService) {
myService.getFooOldSchool(function(data) {
$scope.foo = data;
});
});
$resource
示例
//create a todo
var todo1 = new Todo();
todo1.foo = 'bar';
todo1.something = 123;
todo1.$save();
//get and update a todo
var todo2 = Todo.get({id: 123});
todo2.foo += '!';
todo2.$save();
//delete a todo
Todo.$delete({id: 123});
主幹示例
Backbone 假設您正在與 RESTful API 進行交互,但允許您覆蓋一種方法,Backbone.sync()
, 如果不。您告訴模型資源在服務器上的位置(URL),然後您可以調用 save()
.
var UserModel = Backbone.Model.extend({
urlRoot: '/user',
defaults: {
name: '',
email: ''
}
});
var user = new Usermodel();
// Notice that we haven't set an `id`
var userDetails = {
name: 'Craig',
email: '[email protected]'
};
// Because we have not set an `id` the server will call
// POST /user with a payload of {name:'Craig', email: '[email protected]'}
// The server should save the data and return a response containing the new `id`
user.save(userDetails, {
success: function (user) {
alert(user.toJSON());
}
});
Ember 示例
Ember 擁有 Ember Data,它在技術上不是核心框架的一部分,但正在努力提供更強大的數據持久性/數據存儲故事。它提供了許多您可以在 ActiveRecord 等服務器端 ORM 中找到的功能,但它是專為瀏覽器中 JavaScript 的獨特環境而設計的。在撰寫本文時,Ember 核心團隊即將發布 v1.0,但尚未發布,許多 Ember 項目只是使用 $.ajax
jQuery 中的方法就像 AngularJS 使用 $http
在上面的例子中。
結論
這篇文章按功能對 JavaScript MV* 框架進行了細分,以深入了解這些框架提供了哪些功能,並使讀者意識到它們實際上非常相似。一旦您了解了框架的功能以及它們如何組合在一起,就可以更輕鬆地快速學習多個框架並為您的項目找到合適的框架。