MVVM框架對比
- MVC和MVP簡介
- MVVM
- Vue.js、Angular.js、Ember、Backbone等框架對比
- 雙向綁定原理
- Virtual DOM
前端由於發展比較迅速,框架的更新迭代也比較快,從最初的 backbone.js 到後來的Ember、Knockout、Angular.js, 再到現在的Vue.js、React。
MVC和MVP簡介
- 視圖(view):用戶界面
- 控制器(controller):業務邏輯
- 模型(model):數據保存
通信方式如下:
- view傳送指令到controller
- controller完成業務邏輯後,model改變狀態
- model將新的數據發送到view,用戶得到反饋
MVC在前端中的典型實踐 Backbone
MVP
- MVP模式將controller改名爲Presenter,同時改變了通信方向
- 各部分之間的通信,都是雙向的。
- view與model不發生聯繫,都通過presenter傳遞。
- view非常薄,不部署任何業務邏輯,被稱爲被動視圖,所有邏輯都部署在Presenter。
MVVM
- 唯一的區別是MVVM採用了雙向數據綁定,view的變動自動反映在view-model。Vue.js、Angular、Ember都採用這種模式;
每一個框架的誕生都是爲了解決客觀存在的問題,所以架構是對客觀不足的妥協。
那麼這麼多MVVM框架的誕生是爲了解決什麼問題?
- 如何處理數據的更新和界面的更新。
Vue.js、Angular、Ember、Backbone 對比
功能
作爲構建應用的基礎,框架必須具備一些重要的功能,比如,視圖綁定、雙向綁定、篩選、可計算屬性、髒屬性、表單驗證等等
功能 | Vue | Angular | Backbone | Ember |
---|---|---|---|---|
可觀察對象(observable) | y | y | y | y |
路由(routing) | y | y | y | y |
視圖綁定(view binding) | y | y | - | y |
雙向綁定(two way binding) | y | y | - | y |
部分視圖(partial view) | y | y | - | y |
篩選列表視圖(filtered list view) | y | y | - | y |
- 可觀察對象:可以被監聽是否發生變化的對象
- 路由
- 視圖綁定:在視圖中使用可觀察對象,讓視圖隨着可觀察對象的變化而自動刷新
- 雙向綁定
- 部分視圖:包含其他視圖的視圖
- 篩選列表視圖:用於顯示根據某些條件篩選出來的對象視圖
靈活性
有時候,框架配合一些現成的插件和庫來使用,可能要比使用框架原生同類功能效果更好,而這種插件和庫幾乎遍地都是(不下數百個),又各有特色。因此,能夠把這些庫和插件整合到MVC框架中也非常重要。
Backbone是其中最靈活的一個框架,因爲它的約定和主張最少。使用Backbone需要你自己作出很多決定。
Ember、Angular、Vue.js 也都還算靈活,可有時候你會發現,就算不喜歡它們的某些實現方法,你也只能默默忍受。 這是在選擇Ember或Angular時必須考慮的。
上手難度
Vue.js
上手比較容易,官方文檔比較清晰。專注於MVVM的ViewModel層,實際的DOM封裝和輸出格式都被抽象爲了Directives和Filters。
Angular 4.0
一開始會讓人大呼過癮,因爲可以利用它幹好多意想不到的事,而且學習難度不高。乍一看讓人覺得很簡單。可是,進了門之後,你會發現後面的路還很長。應該說這個框架比較複雜,而且有不少標新立異之處。想看着它的文檔上手並不現實,因爲Angular製造的概念很多,而文檔中的例子又很少。
Backbone
Backbone的基本概念非常容易理解。但很快你會發現它對怎麼更好地組織代碼並沒有太多主張。爲此,你得觀摩或閱讀一些教程,才能知道在Backbone中怎麼編碼最好。而且,你會發現在有了Backbone的基礎上,還得再找一個庫(比如Marionette或Thorax)跟它配合才能得心應手。正因爲如此,我不認爲Backbone是個容易上手的框架。
Ember
Ember的上手難度與Angular有一拼,我認爲學習Ember比學習Angular總體上容易一些,但它要求你一開始就要先搞懂一批基本概念。而Angular呢,一開始不需要這麼費勁也能做一些讓人興奮不已的事兒。Ember缺少這種前期興奮點。
社區支持
能輕易找到參考資料和專家幫忙嗎?
Backbone的社區很大,這是人所共知的事實。關於Backbone的教程也幾乎汗牛充棟,StackOverflow和IRC社區非常熱鬧。
Angular和Ember社區也相當大,教程什麼的同樣不少,StackOverflow和IRC也很熱鬧,但還是比不上Backbone。
Vue的社區比較一般,可能是由於框架還處於發展階段,還未達到上述幾個框架的穩定和成熟。
有沒有插件或庫構成的生態系統?
Backbone的選擇是最多的,可用插件俯拾皆是,這一點讓其他框架都望塵莫及。Angular的生態圈加上Angular UI還是很令人矚目的。我覺得Ember的下游生態雖然欠發達,但Ember本身很受歡迎, 所以前景十分樂觀。
文件大小
Vue和Angular是唯二不需要其他庫就能使用的,其他幾個框架都需要依賴。
Backbone至少需要 Underscore 和 Zepto。雖然在Underscore中可以使用最小的模板來渲染視圖,但多數情況下,還要藉助更好的模板引擎,比如 Mustache 。
Ember 需要 jQuery 和 Handlebars。
Vue | Angular | Backbone | Ember |
---|---|---|---|
18kb | 80kb | 61kb | 269kb |
成熟度
這個框架成熟嗎,經過實際檢驗了嗎,有多少網站在用它呢?
使用Backbone的網站不計其數。最近兩年,它的核心代碼沒怎麼改過,這是成熟的一個重要標誌。
Ember已經不是新框架了,但它的重大變更還是經常有,前幾月剛剛穩定下來。因此,目前還不能說它是個成熟的框架。
Angular似乎比Ember更穩定,驗證的示例也更多,但不能與Backbone相提並論。
Vue 屬於一個新項目,2014-3-20 發佈的0.10.0 Release Candidate版本。
雙向綁定
this.showLoading = false
this.cmsData = data
this.showDownload = data.template.isDownload
this.topBar.displaySharebutton = data.displaySharebutton
this.topBar.title = data.template.title
雙向綁定的基本原理是通過屬性的讀寫器來實現。
function Person() {
var name = ”;
var friends = [];
Object.defineProperty(this, ‘name’, {
get: function () {
console.log(‘get!’)
return name;
},
set: function (value) {
name = value;
friends.push(name)
}
});
this.getFriends = function() {
return friends;
};
}
Virtual DOM
最近一兩年前端最火的技術莫過於ReactJS,即便你沒用過也該聽過,ReactJS由業界頂尖的互聯網公司facebook提出,其本身有很多先進的設計思路,比如頁面UI組件化、虛擬DOM等。
爲什麼需要虛擬DOM?
DOM是很慢的,其元素非常龐大,頁面的性能問題鮮有由JS引起的,大部分都是由DOM操作引起的。如果對前端工作進行抽象的話,主要就是維護狀態和更新視圖;而更新視圖和維護狀態都需要DOM操作。其實近年來,前端的框架主要發展方向就是解放DOM操作的複雜性。
理解虛擬DOM
虛擬的DOM的核心思想是:對複雜的文檔DOM結構,提供一種方便的工具,進行最小化地DOM操作。這句話,也許過於抽象,卻基本概況了虛擬DOM的設計思想。
- 提供一種方便的工具,使得開發效率得到保證;
- 保證最小化的DOM操作,使得執行效率得到保證;
“
//設置虛擬dom的相關屬性
var VElement = function(tagName, props, children) {
//保證只能通過如下方式調用:new VElement
if (!(this instanceof VElement)) {
return new VElement(tagName, props, children);
}
//可以通過只傳遞tagName和children參數
if (util.isArray(props)) {
children = props;
props = {};
}
this.tagName = tagName;
this.props = props || {};
this.children = children || [];
this.key = props ? props.key : void 666;
var count = 0;
util.each(this.children, function(child, i) {
if (child instanceof VElement) {
count += child.count;
} else {
children[i] = '' + child;
}
count++;
});
this.count = count;
};
通過VElement,我們可以很簡單地用js表示DOM結構。
var vdom = VElement('div', { 'id': 'container' }, [
VElement('h1', { style: 'color:red' }, ['simple virtual dom']),
VElement('p', ['hello world']),
VElement('ul', [VElement('li', ['item #1']), VElement('li', ['item #2'])])
]);
上面的javascript代碼可以表示如下DOM結構:
<div id="container">
<h1 style="color:red">simple virtual dom</h1>
<p>hello world</p>
<ul>
<li>item #1</li>
<li>item #2</li>
</ul>
</div>
比對兩棵DOM樹的差異
在用JS對象表示DOM結構後,當頁面狀態發生變化而需要操作DOM時,我們可以先通過虛擬DOM計算出對真實DOM的最小修改量,然後再修改真實DOM結構(因爲真實DOM的操作代價太大)。
- 如何比較兩棵DOM樹
function diff(oldTree, newTree) {
//節點的遍歷順序
var index = 0;
//在遍歷過程中記錄節點的差異
var patches = {};
//深度優先遍歷兩棵樹
dfsWalk(oldTree, newTree, index, patches);
return patches;
} - 如何記錄節點之間的差異
- 對真實DOM進行最小化修改
針對DOM的處理,可分爲:
- 修改節點屬性 PROPS
- 修改節點文本內容 TEXT
- 替換原有節點 REPLACE
- 調整子節點,包括移動、刪除 REORDER