A. vue是怎麼將數據綁定到組件的原理
vue將數據綁定到組件的原理如下:
1、當實例化一個Vue構造函數,會執行 Vue 的 init 方法,在 init 方法中主要執行三部分內容,一是初始化環境變數,而是處理 Vue 組件數據,三是解析掛載組件。以上三部分內容構成了 Vue 的整個執行過程。
2、Vue 實現了一個觀察者-消費者(訂閱者)模式來實現數據驅動視圖。通過設定對象屬性的 setter/getter 方法來監聽數據的變化,而每個屬性的 setter 方法就是一個觀察者, 當屬性變化將會向訂閱者發送消息,從而驅動視圖更新。
3、Vue 的訂閱者 watcher 實現在/src/watchr.js。構建一個 watcher 最重要的是 expOrFn 和 cb 兩個參數,cb 是訂閱者收到消息後需要執行的回調,一般來說這個回調都是視圖指令的更新方法,從而達到視圖的更新,但是這也不是必須的,訂閱回調也可以是一個和任何無關的純函數。一個訂閱者最重要的是要知道自己訂閱了什麼,watcher 分析 expOrFn 的 getter 方法,從而間接獲得訂閱的對象屬性。
4、Vue 雙向數據綁定實現
數據與視圖的綁定與同步,最終體現在對數據的讀寫處理過程中,也就是 Object.defineProperty() 定義的數據 set、get 函數中。Vue 中對於的函數為 defineReactive,在精簡版實現中,我只保留了一些基本特性:
function defineReactive(obj, key, value) {
var dep = new Dep()
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter() {
if (Dep.target) {
dep.depend()
}
return value
},
set: function reactiveSetter(newVal) {
if (value === newVal) {
return
} else {
value = newVal
dep.notify()
}
}
})
}
在對數據進行讀取時,如果當前有 Watcher(對數據的觀察者吧,watcher 會負責將獲取的新數據發送給視圖),那將該 Watcher 綁定到當前的數據上(dep.depend(),dep 關聯當前數據和所有的 watcher 的依賴關系),是一個檢查並記錄依賴的過程。而在對數據進行賦值時,如果數據發生改變,則通知所有的 watcher(藉助 dep.notify())。這樣,即便是我們手動改變了數據,框架也能夠自動將數據同步到視圖。
B. 實現雙向數據綁定
MVVM框架主要包含3個部分: model 、 view 和 viewmodel 。
簡單的來說,就是框架的控制器層(這里的控制器層是一個泛指,可以理解為控制view行為和聯系model層的中間件)和UI展示層(view層)建立一個雙向的數據通道。當這兩層中的任何一方發生變化時,另一層將會自動作出相應的變化。
一般來說要實現這種雙向數據綁定,在前端我目前了解的有三種形式:
目前angular,regular的實現都是基於臟檢查。當發生某些特定的事情的時候,框架會調用相關的digest方法。內部邏輯就是遍歷所有的 watcher ,對監控的屬性做對比。如果值發生了變化,則執行相應的 handler 。
當系統進入臟檢查階段,遍歷所有的 $watch 綁定的 watcher ,然後對比 watcher.get() 與 watcher.last ,如果不同則運行對應的 watcher.fn(newvalue, oldvalue) 。然後再進入下一個watcher的檢查。
何時進行臟檢查?
由於regularjs是基於臟檢查,所以當不是由regularjs本身控制的操作(如事件、指令)引起的數據操作,可能需要你手動的去同步data與view的數據. $update方法即幫助將你的data同步到view層.
]( https://regularjs.github.io/reference?syntax-zh#bind-once )元素來控制你的觀察者數量。
使用ES7中的 Object.observe 方法對對象(或者其屬性)進行監控觀察,一旦其發生變化時,將會執行相應的handler。這是目前監控屬性數據變更最完美的一種方法,語言(瀏覽器)原生支持,沒有什麼比這個更好了。唯一的遺憾就是目前支持廣度還不行,有待全面推廣。
vue.js和avalon.js實現數據雙向綁定的原理就是屬性訪問器。
它使用了ES5中的定義標准屬性的Object.defineProperty 方法。
Object.defineProperty 使用示例:
首先,vuejs在實例化的過程中,會對遍歷傳給實例化對象選項中的data 選項,遍歷其所有屬性並使用 Object.defineProperty 把這些屬性全部轉為 getter/setter。
同時每一個實例對象都有一個watcher實例對象,他會在模板編譯的過程中,用getter去訪問data的屬性,watcher此時就會把用到的data屬性記為依賴,這樣就建立了視圖與數據之間的聯系。當之後我們渲染視圖的數據依賴發生改變(即數據的setter被調用)的時候,watcher會對比前後兩個的數值是否發生變化,然後確定是否通知視圖進行重新渲染。這樣就實現了所謂的雙向數據綁定。