對於MVVM的理解 由 Model、View、ViewModel 三部分構成,由MVC衍生。 Model: 層代表數據模型,也可以在Model中定義數據修改和操作的業務邏輯, View: 代表UI 組件,它負責將數據模型轉化成UI 展現出來, ViewModel: 是一個同步View 和 Model ...
對於MVVM的理解
由 Model、View、ViewModel 三部分構成,由MVC衍生。
Model: 層代表數據模型,也可以在Model中定義數據修改和操作的業務邏輯,
View: 代表UI 組件,它負責將數據模型轉化成UI 展現出來,
ViewModel: 是一個同步View 和 Model的對象。
在MVVM架構下,View 和 Model 之間並沒有直接的聯繫,而是通過ViewModel進行交互,Model 和 ViewModel 之間的交互是雙向的, 因此View 數據的變化會同步到Model中,而Model 數據的變化也會立即反應到View 上。 (註意)
ViewModel 通過雙向數據綁定把 View 層和 Model 層連接了起來,而View 和 Model 之間的同步工作完全是自動的,無需人為干涉,因此開發者只需關註業務邏輯,不需要手動操作DOM, 不需要關註數據狀態的同步問題,複雜的數據狀態維護完全由 MVVM 來統一管理。
Vue.js雙向數據原理
Vue.js 可以說是MVVM 架構的最佳實踐,專註於 MVVM 中的 ViewModel,不僅做到了數據雙向綁定,而且也是一款相對來比較輕量級的JS 庫,API 簡潔,很容易上手。
Vue.js 是採用 Object.defineProperty 的 getter 和 setter,並結合觀察者模式來實現數據綁定的。當把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 將它們轉為 getter/setter。用戶看不到 getter/setter,但是在內部它們讓 Vue 追蹤依賴,在屬性被訪問和修改時通知變化。(註意:據悉vue3.0將採用Proxy替代Object.defineProperty)
圖的解析:
Observer :數據監聽器,能夠對數據對象的所有屬性進行監聽,如有變動可拿到最新值並通知訂閱者,內部採用Object.defineProperty的getter和setter來實現 。
Compile :指令解析器,它的作用對每個元素節點的指令進行掃描和解析,根據指令模板替換數據,以及綁定相應的更新函數 。
Watcher :訂閱者,作為連接 Observer 和 Compile 的橋梁,能夠訂閱並收到每個屬性變動的通知,執行指令綁定的相應回調函數 。
Dep :消息訂閱器,內部維護了一個數組,用來收集訂閱者(Watcher),數據變動觸發notify 函數,再調用訂閱者的 update 方法 。
執行過程:
當執行 new Vue() 時,Vue 就進入了初始化階段,一方面Vue 會遍歷 data 選項中的屬性,並用 Object.defineProperty 將它們轉為 getter/setter,實現數據變化監聽功能;另一方面,Vue 的指令編譯器Compile 對元素節點的指令進行掃描和解析,初始化視圖,並訂閱 Watcher 來更新視圖, 此時Wather 會將自己添加到消息訂閱器中(Dep),初始化完畢。
當數據發生變化時,Observer 中的 getter 方法被觸發(註意這裡觸發什麼),getter 會立即調用Dep.notify(),Dep 開始遍歷所有的訂閱者,並調用訂閱者的 update 方法,訂閱者收到通知後對視圖進行相應的更新。同理當表單輸入內容發生變化時, 就會觸發setter,watcher監聽機制就會執行, watcher通知Vue生成新的VDOM樹,再通過render函數進行渲染,生成真實DOM 。
通過 Object.defineProperty 實現見簡單的雙向數據綁定:
<body>
<div id="demo"></div>
<input type="text" id="inp">
</body>
<script>
let obj = {};
let demo = document.querySelector('#demo');
let inp = document.querySelector('#inp');
Object.defineProperty(obj,'name',{
get : () => {
return inp.value;
},
set : (newVal) => {//當該屬性被賦值的時候觸發
inp.value = newVal;
demo.innerHTML = newVal;
}
});
inp.addEventListener('input',(e) => {
// 給obj的name屬性賦值,進而觸發該屬性的set方法
obj.name = e.target.value;
})
obj.name = 'huqinggui';//在給obj設置name屬性的時候,觸發了set這個方法
</script>
為什麼vue3.0要用Proxy替代Object.defineProperty 實現雙向數據綁定
替換不是因為不好,是因為有更好的方法使用效率更高