1 MVVM模式
Model-View-ViewModel源自MVC模式,核心是ViewModel,ViewModel作為一個“中轉站”,對接Model層獲得並轉換數據使得數據易管理、便於View層使用,又對接View層進行雙向的數據綁定。MVVM框架利用ViewModel這一層幫助開發者們做好了之前jQuery時代低效的查找、操作DOM的工作。View最終展現的不僅是Model的數據,也是經過ViewModel加工後數據。
"雖然沒有完全遵循 MVVM 模型,但是 Vue 的設計也受到了它的啓發。因此在文檔中經常會使用 vm (ViewModel 的縮寫) 這個變量名錶示組件實例"
2 Vue雙向數據綁定
從設計思想來説,Vue採用的MVVM模式是雙向綁定的。Vue實例即充當MVVM中ViewModel層,Model驅動View更新,View層模板進行編譯後Vue實例內部數據也會更新。從開發者使用的角度來説,Vue並沒有提供類似AngularJS雙向數據綁定的API。雖然它通過提供v-model這個語法糖提供了部分雙向數據綁定的能力。Vue實際上是單向的數據驅動視圖。
<input v-model="inputData" />
等價於
<input :value="inputData" @input="inputData = $event.target.value"/>
3 數據驅動視圖
視圖是由數據驅動生成的,對視圖的修改,不是直接操作DOM而是通過修改數據。通過利用虛擬DOM,Vue實現了數據驅動視圖。整體看一下從創建Vue實例到最後渲染到頁面發生的過程。如圖:
數據驅動生成視圖的過程:
1)初始化Vue:Vue是一個類,new Vue({...})操作調用構造函數完成合並配置、初始化生命週期、事件中心,初始化Injections、state(props|data|methods|computed|watch)、provide等;
2)掛載Vue實例到el:校驗頁面上的掛載點el,並拿到對應的template;
3)模板編譯:由template編譯出render()函數,經過一系列的compileToFunctions-createCompiler-createCompilerCreator後,最後Parse出ast,經過優化ast,最終生成render代碼;
4)調用render():將自定義配置中的數據和頁面模板生成的數據結合後,生成VDOM;
5)update和patch上一步的VDOM出DOM:patch提供了鈎子函數,在回調中做相應的處理生成DOM。
4 響應式原理
響應式原理指的是Vue中數據變化驅動視圖更新。實現的關鍵兩個點:
1)將數據變成響應式數據;
2)實現一個觀察者模式:進行依賴收集和派發更新。
響應式數據是指通過代理對象的方式給數據添加上getter、setter屬性特性,從而使對數據的訪問、更新操作是可觀測的。Vue2使用Object.defineProperty()方法,Vue3使用的是Proxy對象。再通過觀察者模式,在訪問數據時進行依賴的收集,在數據更新時派發通知給之前收集到的依賴做更新處理。具體來説,在Vue內部,通過Observer類將數據遞歸地轉化成可觀測對象,最終生成的響應式數據對象,是一個包含了__ob__屬性的對象。在其內部定義、並調用了一系列處理函數:如walk()\defineReactive()。
依賴收集:發生在訪問響應式數據觸發getter函數時,收集的依賴指的是渲染Watcher,收集動作的主體即為響應式數據本身。具體來説Vue內部實現了一個管理Watcher的Dep類(內部維護了一個數組),每個響應式數據對象屬性值的 getter都持有一個 dep的引用。當完成一次render調用後,會觸發所有響應式數據的 getter,從而完成響應式數據Watcher的收集的過程。
派發更新:發生在更新響應式數據觸發setter函數時,實際上就是把之前收集好的Watcher依賴從隊列中取出來執行其update()方法的過程。其中Vue也做了一些優化,並不會每次數據改變都觸發 watcher 的回調執行,而是把這些watcher先添加到一個隊列裏,然後在nextTick後執行 flushSchedulerQueue,利用JavaScript提供的事件隊列的這種異步的方式執行更新動作。
5 Vue2和Vue3響應式原理的區別
Vue2使用Object.defineProperty(),Vue3使用的是Proxy。相比Object.defineProperty(),Proxy()不僅可以解決無法觀測對象新增刪除屬性、無法觀測數組通過索引設值、長度變化的問題,其API更為豐富。對比Object.defineProperty()觀測對象的屬性,Proxy代理的是對象,性能也更好。
Object.defineProperty()之所以不支持數組,是因為Vue基於性能考慮沒有用,而不是因為它不支持。
參考:
Vue技術揭秘
https://ustbhuangyi.github.io...
https://www.cnblogs.com/iovec...