不要聽吹牛逼什麼前端MVVM框架就是好,其實都是一幫沒學好分層設計的搞出來的,讓你完全看清前端MVVM的本質

最近前端圈子裏面,發現你們都在熱炒概念,什麼knockout,angularJs,都被捧成神了,鄙人不才,最近心情也很差,特意寫這篇文章來找罵html

寫代碼的碼農都知道,Java社區雖然不是一個提出分層思想的,確實貫徹的最好的,現在是個Java開發都不會不知道SSH的開發模式,從MVC到MVVM的概念的熱炒,其實真沒什麼技術進步前端

(若是你以爲本文言辭激烈,過於憤世嫉俗,實在看不下去,歡迎移步另外一位園友的分層進化史科普文章http://www.cnblogs.com/indream/p/3602348.html) java

先看什麼是MVVM編程

image

View通常就是咱們日常說的HTML文本的Js模板,裏面能夠嵌入一些js模板的代碼,好比Mustache,好比jstl相似的模板僞代碼多線程

ViewModule層裏面就是咱們對於這個視圖區域的一切js可視業務邏輯,舉個例子,好比圖片走馬燈特效,好比表單按鈕點擊提交,這些自定義事件的註冊和處理邏輯都寫在ViewModule裏面了框架

Module就更簡單了,就是對於純數據的處理,好比增刪改查,與後臺CGI作交互異步

 

那麼什麼是MVVM框架呢??通常他們都是這麼作的性能

1.  定義一串所謂的僞模板代碼,例如經過className標註,或者自定義tag的方式,將一段html文本區域給標註聲明起來,意思就是喊一嗓子,「喂,兄弟們,這塊地方我佔了,要拉屎去別處拉去」學習

2.  經過相似jstl之類lamda表達式,來作js模板,「拜託夥計,天堂有路你不走,非要本身搞一套,你就不能暴露接口讓你們用本身的模板語言,好比Mustache或者jtpl嗎?」spa

3.  很傻比的封裝一串本身的所謂數據模塊組件,與不一樣類型的數據源作數據傳輸和適配,通常都不會分層很清晰,加入後臺數據字段改了,寫框架的都沒腦子的,歷來不作數據字段的自定義適配(舉個例子,原來後臺傳遞的字段是person.userName,如今改爲了小寫,person.username,你就傻逼的去吧模板再改一下吧,其實要解決這個問題,很是簡單,在MVVM層中引入一層DO,領域對象層,Module到DO之間還有一層轉換就能夠搞定這個問題)

4.  非不暴露本身的自定義事件模型,就是那個觀察者模式啦,本身亂七八招在頁面上綁定一堆form change之類的事件,以實現View與Module的單向綁定

5.  所謂的雙向綁定,也就是OOP語言中早被爛透了的getter,setter模型,ES5+能夠用defineProperty,低版本就須要本身在js object賦值的時間作寫死代碼方式的處理了

 

咱們再來看細節

1. 雙向綁定

號稱是最難理解的地方,實際上是框架的做者根本就沒理解Java社區對於軟件開發分層理解的精髓

image

標準的數據驅動開發,應該如上圖所示,在一個View的生命週期內,一個ViewModule會管理一個DomainObject(業務模型),一個DO可能包括多個Module數據模型,一個Module可能來自多個數據源,而不是想不少所謂的MVVM框架那樣強迫一個M來一個數據源

按照上圖標準分層方式來劃分的好處,在於,邏輯清晰,Module層粒度夠細,能夠被屢次複用

DO層與VM層View層屬於一一對應關係,方便對數據作增刪改查的同步

每一層應該是獨立的,非必定要使用MVVM框架的緊耦合,能夠用本身使用不一樣的js插件或者模塊實現MVVM

咱們拋棄框架,單純的看數據,其實咱們要解決的問題很簡單

a) 當DO對象屬性放生變化時候,通知View更新

b) 當View上表單值放生變化時,通知DO更新,並異步通知隊列同步到數據源

先來看問題a,這個最簡單,DO是一個基本的Javascript Object,咱們在View上的模板顯示是這個Object.property,

改變一個Object對象的方式無非幾種,一種是

a) 顯示Object.property = ‘我是傻逼’

b) xxxx.methodName(Object, ‘property’, ‘我是傻逼’)

c) xxxx.merge(Object, {‘property’: ‘我是傻逼’})

若是是a的狀況,ES5+,能夠經過設置Object.defefineProperty(‘property’,{set: functiono(){},get:function(){}}),來作賦值和取值的監控觸發

對於IE8一下,由於js不支持運算符重載,因此暫時沒有好的辦法,因此若是隻考慮移動端的話,直接defineProperty就所有搞定,若是是要考慮PC的話,就不建議開發者使用直接賦值的方式,參考java的開發模式,也是推薦OOP時候,使用set方式賦值,而不是直接=賦值

固然了,若是你非要兼容IE8一下的話,用定時器作輪訓,配合for in 反射,經過髒數據與原始備份對比的方法也是一種辦法,不過這種辦法在當前頁面很是耗性能,因爲IE8一下不支持多線程,HTML5 worker,若是將來flash 插件支持多線程的話,卻是能夠用js和flash插件作線程交互的方式作髒數據檢測

若是是b的狀況,那就太簡單了,在methodName裏面觸發對於該屬性修改的回調便可,如何註冊回調呢,首先咱們要實現一個相似Dom Event的自定義對象的Event模型,而後經過相似Dom Event的註冊事件方式,註冊觀察者,訂閱事件,當執行了methodName時候,發送消息,通知全部訂閱者執行回調

若是是c的狀況,相似b同樣處理

這樣一看,雙向數據綁定的問題就很是簡單的解決了

 

咱們再來看另一個MVVM的問題,非簡單數據模型,複合數據模型(DO的屬性值不是一個string,而是一個Object,且這個Object可能還嵌套多層Obejct的時候)的處理辦法,這個通常的MVVM框架直接不考慮,或者經過長字段名的方式繞過這個問題

這個問題是這樣的,早在10幾年前,java structs框架流行的時候就出現了,當一個表單,出現須要對兩個Java Bean作update操做時候,一個bean是user,一個bean是成績

對應的表單字段名,就是 user表.name,user表.id,score表.point,

在struct2裏面,處理邏輯是把 「點」做爲特殊符號,在作form序列化時候,非包含點的字段的值都是string,包含點的字段是一個Object,好比剛纔的form序列化以後結果就是 { user: {id :’’ , name: ‘’}, score: {id: ‘’, point: ‘’}}

同理在MVVM實現時,也是同樣,認爲點是分割對象的關鍵字,這樣咱們就能夠實現把多個對象嵌套到View模板裏面,實現複合Object的雙向映射

 

最後一個問題,也就是高級MVVM編程裏面必需要面對的問題,就是自定義事件的廣播和冒泡,我看過大多數的MVVM框架,對於廣播,這塊有部分實現了,可是對於冒泡一個都沒實現

其實這個真的不是很複雜的問題,事件廣播,這個最簡單,三歲小孩都能寫,咱們在註冊回調時候,不是有一個事件隊列嗎,在回調時候,經過特殊標記位,控制是否繼續擴散廣播,仍是執行完畢終止便可

而自定義事件的冒泡要騷騷複雜一些,他是因爲OOP編程裏面的繼承和包含關係引伸而來的,咱們先說包含關係,前面說了MVVM框架裏面,都會聲明一塊地方爲VM控制區域,通常垃圾的框架都不會考慮,VM嵌套的狀況,由於圖簡單嗎

可是實際開發過程當中,你會遇到不少這種狀況,就是VM複用的問題,通常都是發現使用了MVVM框架以後,發現VM定義的太大,無法複用,若是要複用VM就又發現VM定義的過小,出現須要VM嵌套的狀況無法用

其實簡單,咱們知道DOM事件是有冒泡的,VM同理,只要在自定義事件模型裏面定義了VM的父子關係,或者同級關聯關係,便可實現VM的自定義事件的廣播和冒泡,另外也解決了VM複用的問題,可讓代碼顆粒度更小

 

另外那種,聲明式編程這種老掉牙的概念就真的別在吵了,還記得10幾年前的structs的tag嗎,js圈子裏面這種經過自定義tag,自定義className,自定義屬性,掛載js來自定識別執行邏輯的例子大把皆是,仍是建議廣大前端開發,不要浮躁,多像java社區學習,多多從根本上了解分層理念的精髓,不要聽了吹牛逼,聽風就是雨,仍是多瞭解原理纔是真理啊

 

最近心情很很差,股票大跌,公司的事情你懂的,寫這篇文檔純屬沒事找事,歡迎廣大道友開罵,來陪我大戰三百回合

相關文章
相關標籤/搜索