mnv*框架開發時代
mnv*框架開發時代
現在前端開發框架顯然已經在mvvm模型時代有發展了一步, virtual dom 提出不久,使用前端代碼來調用native的思路就開始被實踐。相信大家也知道是什么東西。到了今天,我們不得不承認, mnv* 框架開發時代正在到來。
mnv 是什么,具體可以這么理解, model-Native-View-* ,而后面的 則可以認為是 virtual dom 或 mvvm 中的 ViewModel ,或者我們也可以自己使用controller來調用Native View。想想這樣定義是非常合適的。
那么我們再看看下從 mv* 走向 mnv* ,我們為什么會看到這樣的變化。
一、直接do
在此之前不得不提下之間的dom交互框架,就是選擇dom進行操作,思路十分直接也很實用,通過dom交互框架,相比JavaScript原生API,我們可以比較高效的處理dom交互和事件綁定了,這種高效的方式給我們到來了效率上的提高,但是頁面大了就不好處理了。
隨著ajax技術的盛行,SPA應用開始被廣泛運用。SPA的引入將整個應用的內容都在一個頁面中進行異步交互。這樣,原有的dom交互方式開發就顯得不好管理,例如某SPA頁面上交互和異步加載的內容很多,我們的做法是每一次請求渲染后做事件綁定,異步請求后再做另一部分事件綁定,后面以此類推,當所有異步頁面全部調用完成,頁面上的綁定將變得十分混亂,各種元素綁定,渲染后的視圖內容邏輯不清,又不得不聲明各種變量保存每次異步加載時返回的數據,因為頁面交互需要對這些數據做操作,最后寫完,項目代碼就成了一鍋粥。
二、前端mvc
為了更方便的統一管理頁面上的事件、數據和視圖內容,就有了早期mvc的框架設計。mvc可以認為是一種設計模式,其基本思路是將dom交互的過程分為調用事件,獲取數據,管理視圖。即將之前所有的事件、數據、視圖分別統一管理。用model來存放數據請求和數據操作,視圖來存放對視圖的操作和改變,controller用來管理各種事件綁定。
例如,SPA中的每個頁面可以看成是一個組件,之前的做法是每個組件獨立完成自己的數據請求操作、渲染和數據綁定,但是組件多了,每個組件自己去做就比較混亂,邏輯比較混亂。到了MVC里面,所有的組件數據請求、渲染、數據綁定都到一個統一的model、view、controller注冊。后面的操作我們就不在管你有多少個組件了,你要調用必須要通過mvc來調。通俗來說就像是組件交出了自己控制權到一個統一的地方注冊調用。
我們看一個mvp的示范,來了解mvp是如何區別于原有dom交互開發方式的:
backbone例子和解釋
5.2.2 前端mvp
MVP可以跟MVC對照起來看。和MVC一樣,MVP的M就是 Model, V就是View,而P,則代表Presenter,它與Controller有點相似。不同的是,在MVC中V會直接展現M,而在MVP中V會把所有的任務都委托給P。V和P會互相持有reference,因此可以互相調用。。
例如我們可以吧MVC代碼上做一點改變,寫成這樣,這樣
<div controller="Controller.vp" id="text">html</div>
var Controller = new Controller();
Controller['vp']= new VP({
$el: $('text'),
click: fn(e){
console.log(self.$el.html());
},
mouseenter: function(e){
console.debug(self.$el.html());
},
mouseleave: function(e){
console.info(self.$el.html());
}
});
這樣將view和Controller的引用關聯了起來,而mvc一般是通過事件監聽或觀察者的異步方式來實現的,我們可以在任意地方定義注冊監聽事件都不會有問題,這樣監聽的事件和觸發這個事件的html元素脫離了引用,當應用復雜起來后要維護dom的交互邏輯就比較麻煩了。而mvp提供了一個簡單的引用,將元素對應的操作于對應的presenter關聯起來。我們要查詢元素對應的controller時只要通過Controller.vp就可以直接調用了,再想想我們的mvc,我們還是得用選擇器。
三、前端mvvm
mvvm概念可以認為是一個自動化的presenter,也這個時候進一步弱化了C層,任何操作都通過viewmodel來驅動。Controller最終在頁面上一directives的形式體現,通過對directive的識別來注冊事件,這樣管理起來就更清晰了。那么什么是directive?這個我們后面統一來講。
先來看看現在的mvvm模式下,我們的頁面組件是如何運作的:
<form action="" id="form">
<label for="text" q-html="label"></label>
<input type="text" q-value="value" q-model="value" q-mydo="number | getValue">
<button q-on="click: submit"></button>
</form>
let viewModel = new VM({
$el: '#form',
data:{
label: '用戶名',
value: '輸入初始值',
number: 0
},
method:{
submit(){
// doSubmit
}
},
directive:{
mydo(value){
console.log(value);
}
},
filter:{
getValue(){
reutrn value ++;
}
}
})
</code></pre>
mvvm設計一個很大的好處是將mvc中controller中的controller注冊到相對應的元素中,讓我們后期維護時很快定位,免去了查看controller中event列表的工作,而且初始化后自動做數據綁定,能將頁面中所有同類操作復用,大大節省了我們自己寫代碼做綁定的代碼量。這段代碼中初始化時自動幫我們就做了數值填充、數據雙向綁定、事件綁定的事情。那么框架怎樣幫我做的呢。我們來看下new VM做了哪些事情:這里傳入了元素、數據、方法列表、自定義directive列表,首先程序找到這個元素,開始對這個元素的屬性節點進行遍歷,一旦遍歷到屬性名稱含有q-開頭的屬性是,認為是mvvm框架自定義的屬性,然后會對屬性的指進行特殊處理;例如遍歷到 q-html="label" 時,將data中的label值賦給這個元素的innerHTML;如果遍歷到 q-on="click: submit" 時,將這這個元素上綁定click事件,事件回調函數為submit;也可以自定義 q-mydo 的指令,遍歷到該節點屬性是,調用directive中的mydo方法,輸入參數為data中的getValue方法返回的值,getValue輸入參數為number值,這里的getValue被稱為過濾器。
這里要知道的是 q- 開頭的指令是框架約定的,不同的框架約定的不一樣,例如 ng- 、 v- 、 ms- 相信也都見過或用過。這里viewModel創建進行綁定的原理就這么簡單,按照這個思路去擴充,就可以自己寫一個mvvm框架。當然完整的框架涉及東西多的多,含有豐富的directive、filter、表達式、vm完善的api和甚至一些兼容性處理等。
再來看下看是的問題,directive、filter這些東西具體是啥?下面我們來看看mvvm設計所涉及的東西:
-
directive。翻譯過來叫指令,簡單地說就是自定義的函數,例如q-html、q-class、q-on、q-show、q-attr等封裝了dom的一些基本重復性的操作。
-
filter。bool、upperCase、lowwerCase等,指用戶希望對數據進行處理一下,然后在交個directive或下一個filter。
-
表達式設計。if-else等,類似頁面模板,其左右也是控制頁面內容
-
viewModel設計。說白了就是說你的數據如何放在內存里,怎么方便的進行讀取、修改等操作。
-
數據變更檢測。我們知道mvvm通常是可以做雙向綁定的,通過view的改變來改變model一般是通過元素各種onchange事件來觸發修改javascript的viewModel的,這點做到比較淺顯。另一方便是viewModel修改了,如何觸發view的自動更新或重渲染呢。通常我們有三種解決思路。
具體數據更變檢測實現可以看我的另一篇文章《 javascript實現數據雙向綁定的三種方式 》。
關于mvvm講的比較多,這里相信大家也對mvvm有了更深的了解,自己也可以去實現一個類似的框架,只是是否必要的問題。總結來說從mvc到mvp,然后到mvvm,前端設計模式的原則仍然是向著易實現、易維護、易擴展的基本方向發展的。但目前位置前端各類框架也已經成熟并開始向上迭代。但是,這還沒有結束,我們依然沒有脫離dom編程的基本套路,一次次框架的改進只是提高了我們的開發效率,但是dom元素的效率仍沒有得到本質的提升。
四、前端virtual dom
為了改進dom交互的效率,或者說是盡量減少dom交互的次數,virtual dom的概念當下十分盛行,目前圈內各種大小團隊紛紛投入項目使用。因為viewModel的改變最終還是要實時操作dom來刷新view層,而dom對象的操作相對于JavaScript對象的操作要慢些,原因很簡單,dom節點對象的內置屬性多了,就創建一個dom對象而言,dom的創建需要處理各種內置屬性的初始化,而如果使用JavaScript對象來描述就簡單了。
五、前端 mnv*
如果說vitual dom減少了dom的交互,那么mnv*想要做的一件事情就是完全拋棄使用dom,那樣就只能在view層做改進了,使用nativeView來代替目前html的view,而交互邏輯依然可以使用ViewModel、virtual Dom或者controller來實現,具體就看實現的方式了。
要做到NativeView的操作,這里與之前不同之處就是調用時通過衍生HTML語法通過解釋器執行nativeView的渲染,這是就需要在native和衍生HTML語法之間添加一層解釋器。
總結下來,前端框架一次次進化,先從效率的方向上提升,然后再性能上完善。目前mnv的開發模式開始進入視線,也在快速地形成和建立生態。但盡管如此,我們如果需要選擇的技術棧方案,當然還是以最適合我們的作為最高原則。切忌過度設計。
來自: http://jixianqianduan.com/frontend-javascript/2016/06/24/mnv-tech.html