王鵬強
摘要:互聯(lián)網(wǎng)的不斷發(fā)展,前端開發(fā)人員一直致力于開發(fā)更加高效的代碼,由于前期網(wǎng)速以及前端語言的限制,始終得不到解決,近年來,這些問題得到解決后,越來越多的前端框架誕生,這些框架都趨向于工程化,不斷提高前端開發(fā)者的開發(fā)效率以及用戶的體驗度。該文就近年來出現(xiàn)的MVVM框架中的Vue做出一些深入的研究,解析MVVM框架的原理及實現(xiàn)。
關(guān)鍵詞:MVVM;VUE;前端
中圖分類號:TP311 文獻標識碼:A
文章編號:1009-3044(2019)11-0097-02
Abstract: With the continuous development of the Internet, front-end developers have been devoting themselves to developing more efficient code. Because of the limitations of network speed and front-end language, they have not been solved. In recent years, after these problems have been solved, more and more front-end frameworks have been born. These frameworks tend to be engineering, and constantly improve the development efficiency of front-end developers and user experience. This paper makes some in-depth research on Vue in MVVM framework, which appears in recent years, and analyses the principle and implementation of MVVM framework.
Key words: MVVM; VUE; Front-end
1 背景
從早期的靜態(tài)HTML頁面,所有的邏輯運算都由后端進行,到1995年網(wǎng)景推出的JavaScript,逐步在客戶端進行部分的邏輯運算,到1999年XMLHTTPRequest的誕生,瀏覽器異步傳輸、局部刷新的實現(xiàn),再到j(luò)Query的出現(xiàn),瀏覽器的開發(fā)逐步從后端走向前端,到今天,各種MVVM框架順應(yīng)時代發(fā)展的潮流,引導(dǎo)前端技術(shù)走向工程化。
2 MVVM框架的產(chǎn)生
前端的飛速發(fā)展,以及互聯(lián)網(wǎng)時代的到來,一個大型web網(wǎng)站項目需要成千上萬個HTML界面組成。前后端的未分離,以及JavaScript與HTML的混合使用,對于網(wǎng)站維護人員來說,無從下手,增加了不必要的難度。web開發(fā)者一直尋求屬于前端的模塊化框架,2009年,AngularJS的誕生,到2011年React和Ember,再到2014年Vue.js的出現(xiàn),標志著屬于前端的工程化框架正在取代以往的開發(fā)模式。
3 MVVM框架的組成
MVVM,全名Model-View-ViewModel,前端開發(fā)者只用關(guān)注數(shù)據(jù),使用數(shù)據(jù)的變化改變DOM,也就是視圖的變化,以往的開發(fā)模式是開發(fā)者在數(shù)據(jù)改變的時候,手動去操作DOM,這樣的開發(fā)模式不僅費時費力,維護時更是難上加難。MVVM通過數(shù)據(jù)的雙向綁定,當(dāng)數(shù)據(jù)發(fā)生變化時,局部界面自動重新渲染,解耦View層,也就是視圖層。
3.1 Model
Model層,也就是數(shù)據(jù)層,用于邏輯處理以及數(shù)據(jù)的處理。這一層,前端開發(fā)者無需關(guān)注后端的數(shù)據(jù)的處理,只需要后端暴露接口,通過后端返回的數(shù)據(jù)格式,前端開發(fā)人員進行相應(yīng)的數(shù)據(jù)處理。
3.2 View
視圖層,用于展示用戶界面,不負責(zé)數(shù)據(jù)的處理,用于數(shù)據(jù)綁定的聲明,指令的聲明,事件綁定的聲明。
3.3 ViewModel
負責(zé)Model層與View層的交互,是其中最重要的一環(huán),將Model的數(shù)據(jù)進行監(jiān)聽,當(dāng)數(shù)據(jù)發(fā)生改變時,及時更新視圖。這一層由框架封裝完成,網(wǎng)站開發(fā)人員只需關(guān)注Model中數(shù)據(jù)的處理,實現(xiàn)數(shù)據(jù)驅(qū)動視圖。
4 MVVM的優(yōu)點
1) 低耦合。View層與Model層相互聯(lián)系,又可以相互獨立,數(shù)據(jù)可以雙向綁定又可以單向傳遞。
2) 組件化。模塊化的應(yīng)用,出現(xiàn)組件的重復(fù)利用,同樣的視圖模板,開發(fā)人員可以重復(fù)利用,提高開發(fā)效率,后期更容易維護。
3) 易于開發(fā)。由于數(shù)據(jù)驅(qū)動視圖,開發(fā)人員更多的重心放在數(shù)據(jù)的處理與業(yè)務(wù)邏輯,極大地提高開發(fā)效率。
5 實現(xiàn)分析
5.1 發(fā)布/訂閱者模式
發(fā)布/訂閱者模式是Vue使用的開發(fā)模式,通過訂閱者訂閱不同的需求,也就是相應(yīng)的數(shù)據(jù)處理,發(fā)布者將Dep中訂閱者依次遍歷執(zhí)行,執(zhí)行對應(yīng)的回調(diào)函數(shù)。
Vue使用Observer監(jiān)聽new Vue()實例對象,通過Watcher添加對應(yīng)的訂閱者,Dep收集這些訂閱者,當(dāng)Data發(fā)生改變時,Observer通知Dep,當(dāng)前數(shù)據(jù)綁定的Dep收集器中的訂閱者依次執(zhí)行,實現(xiàn)數(shù)據(jù)雙向綁定。Compile指令解析器解析HTML模板中的指令,將對應(yīng)的解析函數(shù)添加進Dep中,數(shù)據(jù)發(fā)生改變時,相應(yīng)的解析函數(shù)會更新視圖。
5.2 Observer的實現(xiàn)
Vue支持IE9及以上,Observer數(shù)據(jù)監(jiān)聽器使用數(shù)據(jù)劫持的方式進行數(shù)據(jù)監(jiān)聽,通過Object.defineProperty()來重新定義屬性的getter和setter。
Object.defineProperty(data,key,{
get:function(){},
set:function(){}
})
當(dāng)對應(yīng)的數(shù)據(jù)需要相應(yīng)的對調(diào)函數(shù)時,在getter中添加對應(yīng)的訂閱者,getter中不再做其他操作,只用來添加對應(yīng)的數(shù)據(jù)依賴。
在setter中,其中做了一部分判斷,當(dāng)數(shù)據(jù)未發(fā)生改變時,不做任何操作,提高程序的運算效率,當(dāng)數(shù)據(jù)發(fā)生改變時,通知Dep(訂閱收集器),執(zhí)行dep.notify(),notify為dep中定義的一個函數(shù),主要用于遍歷Dep中的所有訂閱者,并執(zhí)行所有訂閱者的回調(diào)函數(shù),更新相應(yīng)的視圖。這個過程是Vue的設(shè)計核心,在這里通過數(shù)據(jù)攔截完成訂閱者的訂閱,發(fā)布者在數(shù)據(jù)改變后,通知所有訂閱者。
5.3 Dep的實現(xiàn)
Dep(訂閱收集器),顧名思義,用于收集對應(yīng)的訂閱者,它其中主要由subs,addSub,notify以及相應(yīng)的sub.update組成。
Subs為一個數(shù)組,保存所有的訂閱者,當(dāng)添加訂閱者時,subs.push(sub)依次添加,每個sub(訂閱者)是獨立的,它具有相應(yīng)的update函數(shù),用于更新視圖和對應(yīng)的自定義回調(diào)函數(shù)。addSub方法用于添加sub,當(dāng)然需要一個調(diào)用這些sub的函數(shù)方法,notify方法用于遍歷subs,這個方法在數(shù)據(jù)的setter方法中執(zhí)行,保證只有數(shù)據(jù)發(fā)生改變,才去通知所有的訂閱者。
5.4 Watcher的實現(xiàn)
Dep中已經(jīng)實現(xiàn)添加訂閱者,具體的每個訂閱者的實現(xiàn)由Watcher實現(xiàn)。在Observer的getter方法中,執(zhí)行相應(yīng)的添加方法,但是如何觸發(fā)getter方法,保證訂閱者只添加一次,Vue在Watcher中做了詳細的操作。
function Watcher(vm, exp, cb) {
this.cb = cb;
this.vm = vm;
this.exp = exp;
this.value = this.get(); // 將自己添加到訂閱器的操作
}
Watcher.prototype={
update:function(){},
run:function(){},
get:function(){}
}
通過new Watcher(),首先緩存自己,保證在Observer的getter方法執(zhí)行時,將自己添加到Dep中,當(dāng)添加完成之后,釋放自己,當(dāng)前屬性再次獲取時,不會二次添加進Dep中。由于傳入到Observer的是當(dāng)前new Watcher()實例,在Dep收集器中的每個sub(訂閱者)都是一個new Watcher()實例對象,每個實例定義它的回調(diào)函數(shù)update,在update中執(zhí)行當(dāng)前訂閱者的需求。到這一步,基本實現(xiàn)了數(shù)據(jù)攔截,數(shù)據(jù)改變驅(qū)動訂閱者方法的執(zhí)行。
5.5 Compile的實現(xiàn)
Compile(指令解析器),以上已經(jīng)實現(xiàn)了雙向綁定,但是整個過程并沒有去改變DOM,只是實現(xiàn)了數(shù)據(jù)的雙向綁定,界面并沒有發(fā)生實際的改變。所以需要一個Compile來解析和綁定DOM。
首先需要獲取當(dāng)前的DOM對象,由于操作DOM過于頻繁會影響瀏覽器的渲染速度,在Vue出現(xiàn)了虛擬DOM,它主要是將對應(yīng)的DOM對象轉(zhuǎn)為js對象,首先去改變js對象,當(dāng)js對象發(fā)生改變時,再去操作DOM改變。
接下來需要遍歷虛擬DOM中的各個節(jié)點,這里我們只負責(zé)研究它的雙向綁定,對其中的{{}}進行解析,對其中的數(shù)據(jù)進行new Watcher()操作,并給Watcher更新視圖的回調(diào)函數(shù)。這樣,數(shù)據(jù)的雙向綁定就完成了,當(dāng)界面的input內(nèi)容發(fā)生改變時,js數(shù)據(jù)也發(fā)生改變,同理,數(shù)據(jù)發(fā)生改變時,界面也同時發(fā)生渲染。
6 結(jié)束語
前端的發(fā)展已經(jīng)是趨勢,MVVM框架已經(jīng)占據(jù)了大部分市場,前端開發(fā)者不再去寫重復(fù)的HTML元素,不用一遍又一遍獲取DOM,操作DOM,既提高了開發(fā)效率,又提高了用戶的使用體驗。SPA(單頁面)應(yīng)用越來越多,HTML5的跨終端性,讓現(xiàn)在MVVM框架走向移動開發(fā),資源只需加載一次,不僅僅是PC,它在逐漸替代傳統(tǒng)的APP,未來的前端越來越趨向于大前端。
參考文獻:
[1] 孫連山, 李云倩. MVVM框架在Web前端的應(yīng)用研究[D]. 上海: 復(fù)旦大學(xué), 2014.
[2] 劉立. MVVM 模式分析與應(yīng)用[J]. 微型電腦應(yīng)用, 2012, 28(12): 57-60.
[3] 何煥春, 楊懌. 基于MVVM構(gòu)架的Web前端框架研究[J]. 電腦知識與技術(shù), 2017, 13(24):59-60.
[4] 莫文水. Web前端中MVVM框架的應(yīng)用研究[J]. 網(wǎng)絡(luò)安全技術(shù)與應(yīng)用, 2017(4): 64.
[5] 易劍波. 基于MVVM模式的WEB前端框架的研究[J]. 信息與電腦: 理論版, 2016(19): 76-77, 84.
【通聯(lián)編輯:謝媛媛】