剖析vue實現原理-如何實現MVVM中的雙向數據綁定
1. 了解vue的雙向數據綁定原理以及核心代碼模塊
2. 學習如何實現雙向綁定
為了便于說明原理與實現,本文相關代碼主要摘自vue源碼,并在開始講解的過程中盡量對代碼進行簡化改造,等基本實現之后再考慮其他情況(例如開始并未考慮到數組的處理、數據的循環依賴等等)
***
下面的代碼就是最后需要實現的功能,語法和vue一模一樣,如果看不懂下面代碼是什么意思,那請先去學習vue。如果no problem,請繼續向下閱讀。
```
放置代碼的區域
```
```
放置最后實現效果的區域,gif動態圖
```
***
端好小板凳,坐直,先聽我叭叭叭的講一些廢話,這些廢話是后面實現思路的一個很好的鋪墊!
MVVM=Model+View+ViewModel
Model和View通訊都是靠著ViewModel這個兩面派(中間商)來進行的。
要想搞清楚雙向數據綁定,就得先搞清楚哪兩個方向,然后再分別搞清楚每個方向如何綁定,最后自然的就搞清楚了雙向數據綁定。
雙向:
一個方向是:數據 ---> 頁面 Model ---> View
一個方向是:頁面 ---> 數據 View ---> Model
先說View ---> Model,這個其實很簡單,就是一些表單組件上綁定input或者change等事件,當事件被觸發時修改Model的數據即可;
再說Model ---> View,這個里面有三個問題需要思考,同時也是三個難點。
1. VM如何知道Model的某個數據發生變化了呢?
2. VM即使知道Model的某個數據發生變化了,那之后又如何通知View重新渲染呢?
3. View收到重新傳染的指令之后,又是如何解析dom并重新傳染dom呢?
**整理一下實現思路:**
1. 實現監聽數據的變化
2. 實現解析DOM模板(即如何實現模板引擎)
3. 實現事件監聽
***
叭叭叭到此結束,帶著上面的實現思路,我們來一一攻克!!!!!!
# 雙向數據綁定
實現思路第一個就是實現監聽數據的變化,那這和實現雙向數據綁定是等同的嗎?我的答案是:yes yes yes!只要實現了這個那就完成50%的工作了。如果你不能理解,請看我下面的辯論:
目前幾種主流的MVC(VM)框架都實現了**單向數據綁定**,而正如我上面的解釋:我所理解的雙向數據綁定無非就是在單向數據綁定的基礎上給一些表單組件上(input、textarea、select、checkbox、radio等)綁定input或者change事件,來動態修改model和 view,并沒有多么高深。所以無需太過介懷是實現的單向數據綁定或雙向數據綁定。
實現數據綁定的做法有大致如下幾種:
- 發布者-訂閱者模式(backbone.js)
- 臟值檢查(angular.js)
- 數據劫持(vue.js)
**發布者-訂閱者模式**: 一般通過sub, pub的方式實現數據和視圖的綁定監聽,更新數據方式通常做法是` vm.set('property', value)`。但是這種方式現在畢竟太low了,我們更希望通過 `vm.property = value`這種方式更新數據,同時自動更新視圖,于是有了下面兩種方式
**臟值檢查**:angular.js 是通過臟值檢測的方式比對數據是否有變更,來決定是否更新視圖,最簡單的方式就是通過`setInterval()`定時輪詢檢測數據變動,當然Google不會這么low,angular只有在指定的事件觸發時進入臟值檢測,大致如下:
- DOM事件:例如input,change,click等等(ng-click)
- XHR響應事件 ( $http )
- 瀏覽器Location變更事件 ( $location )
- Timer事件( $timeout , $interval )
- 執行 $digest() 或 $apply()
**數據劫持**:vue.js 則是采用數據劫持結合發布者-訂閱者模式的方式,通過`Object.defineProperty()`來劫持各個屬性的setter,getter。在數據變動時發布消息給訂閱者,觸發相應的監聽回調。
# 圖解思路
已經了解到vue是通過數據劫持的方式來做數據綁定的,其中最核心的方法便是通過`Object.defineProperty()`來實現對屬性的劫持,達到監聽數據變動的目的,無疑這個方法是本文中最重要、最基礎的內容之一,**如果不熟悉`defineProperty`,請先學習**。
整理了一下,要實現mvvm的雙向綁定,就必須要實現以下幾點:
1. 實現一個數據監聽器Observer
能夠對數據對象的所有屬性進行監聽,如有變動可拿到最新值并通知訂閱者
2. 實現一個指令解析器Compile
對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數
3. 實現一個Watcher
作為連接Observer和Compile的橋梁,能夠訂閱并收到每個屬性變動的.通知,執行指令綁定的相應回調函數,從而更新視圖
4. 實現Vue入口函數
整合以上三者
下圖是我在網上找到的兩張圖,本人作圖能力有限,就給盜用了,希望博主不要怪罪于我


所有思路我們都已經整理完畢,并且用兩張大圖也表述了它們之間的關系,也比較明確相關邏輯和模塊功能了,下面就要開始上代碼了。當然,我會在代碼中加入詳盡的注釋,以幫助大家理解。
# 具體實現
## 1. 實現Observer
Observer模塊的職責就是劫持屬性的變化,