之前對 MVVM 模式一直只是模模糊糊的認識,正所謂沒有實踐就沒有發言權,通過這兩年對 Vue 框架的深入學習和項目實踐,終於有了撥開雲霧見月明的感覺。在此記錄一下,算是拋磚了。 ...
之前對 MVVM 模式一直只是模模糊糊的認識,正所謂沒有實踐就沒有發言權,通過這兩年對 Vue 框架的深入學習和項目實踐,終於
可以裝B了有了撥開雲霧見月明的感覺。
簡而言之
Model–View–ViewModel(MVVM) 是一個軟體架構設計模式,由微軟 WPF 和 Silverlight 的架構師 Ken Cooper 和 Ted Peters 開發,是一種簡化用戶界面的事件驅動編程方式。由 John Gossman(同樣也是 WPF 和 Silverlight 的架構師)於2005年在他的博客上發表。
MVVM 源自於經典的 Model–View–Controller(MVC)模式(期間還演化出了 Model-View-Presenter 模式,可忽略不計)。MVVM 的出現促進了 GUI 前端開發與後端業務邏輯的分離,極大地提高了前端開發效率。MVVM 的核心是 ViewModel 層,它就像是一個中轉站(value converter),負責轉換 Model 中的數據對象來讓數據變得更容易管理和使用,該層向上與視圖層進行雙向數據綁定,向下與 Model 層通過介面請求進行數據交互,起呈上啟下作用。如下圖所示:
MVVM 已經相當成熟了,主要運用但不僅僅在網路應用程式開發中。KnockoutJS 是最早實現 MVVM 模式的前端框架之一,當下流行的 MVVM 框架有 Vue,Angular 等。
組成部分
簡單畫了一張圖來說明 MVVM 的各個組成部分:
分層設計一直是軟體架構的主流設計思想之一,MVVM 也不例外。
- View 層
View 是視圖層,也就是用戶界面。前端主要由 HTML 和 CSS 來構建,為了更方便地展現 ViewModel 或者 Model 層的數據,已經產生了各種各樣的前後端模板語言,比如 FreeMarker、Marko、Pug、Jinja2等等,各大 MVVM 框架如 KnockoutJS,Vue,Angular 等也都有自己用來構建用戶界面的內置模板語言。
- Model 層
Model 是指數據模型,泛指後端進行的各種業務邏輯處理和數據操控,主要圍繞資料庫系統展開。後端的處理通常會非常複雜:
後端:“我們這裡的業務邏輯和數據處理會非常複雜!”
前端:“關我屁事!”
但是再複雜跟我們前端也沒有半毛錢關係,只要後端保證對外介面足夠簡單就行了,我請求api,你把數據返出來,咱倆就這點關係,其他都扯淡。
- ViewModel 層
ViewModel 是由前端開發人員組織生成和維護的視圖數據層。在這一層,前端開發者對從後端獲取的 Model 數據進行轉換處理,做二次封裝,以生成符合 View 層使用預期的視圖數據模型。需要註意的是 ViewModel 所封裝出來的數據模型包括視圖的狀態和行為兩部分,而 Model 層的數據模型是只包含狀態的,比如頁面的這一塊展示什麼,那一塊展示什麼這些都屬於視圖狀態(展示),而頁面載入進來時發生什麼,點擊這一塊發生什麼,這一塊滾動時發生什麼這些都屬於視圖行為(交互),視圖狀態和行為都封裝在了 ViewModel 里。這樣的封裝使得 ViewModel 可以完整地去描述 View 層。由於實現了雙向綁定,ViewModel 的內容會實時展現在 View 層,這是激動人心的,因為前端開發者再也不必低效又麻煩地通過操縱 DOM 去更新視圖,MVVM 框架已經把最臟最累的一塊做好了,我們開發者只需要處理和維護 ViewModel,更新數據視圖就會自動得到相應更新,真正實現數據驅動開發。看到了吧,View 層展現的不是 Model 層的數據,而是 ViewModel 的數據,由 ViewModel 負責與 Model 層交互,這就完全解耦了 View 層和 Model 層,這個解耦是至關重要的,它是前後端分離方案實施的重要一環。
舉個慄子
扯了這麼多,並沒有什麼卵用。千言萬語不如一個慄子來的乾脆,下麵用一個 Vue 實例來說明 MVVM 的具體表現。
Vue 的 View 模板:
<div id="app">
<p>{{message}}</p>
<button v-on:click="showMessage()">Click me</button>
</div>
Vue 的 ViewModel 層(下麵是偽代碼):
var app = new Vue({
el: '#app',
data: { // 用於描述視圖狀態(有基於 Model 層數據定義的,也有純前端定義)
message: 'Hello Vue!', // 純前端定義
server: {}, // 存放基於 Model 層數據的二次封裝數據
},
methods: { // 用於描述視圖行為(完全前端定義)
showMessage(){
let vm = this;
alert(vm.message);
}
},
created(){
let vm = this;
// Ajax 獲取 Model 層的數據
ajax({
url: '/your/server/data/api',
success(res){
// TODO 對獲取到的 Model 數據進行轉換處理,做二次封裝
vm.server = res;
}
});
}
})
服務端的 Model 層(省略業務邏輯處理,只描述對外介面):
{
"url": "/your/server/data/api",
"res": {
"success": true,
"name": "IoveC",
"domain": "www.cnblogs.com"
}
}
這就是完整的 MVVM 編程模式。
代碼執行之後雙向綁定的效果如下:
嘿嘿,前後端可以成功分手了,以後再也不用關心後端個錘子開發進度\暴怒臉,複雜實現,blabla...,盡情享用前端如絲般順滑的開發快感吧:)