Vue是如何實現雙向數據綁定的
1、實現雙向綁定的基本原理
vue實現數據雙向綁定主要是采用數據劫持結合發布者-訂閱者模式的方式。
數據劫持是通過Object.defineProperty()實現的,該函數為每個屬性添加setter,getter 的方法,在數據發生改變時 setter 方法會被觸發,然後發布消息給訂閱者,觸發相應監聽回調。當把一個普通 Javascript 對象傳給 Vue 實例來作為它的 data 選項時,Vue 將遍歷它的屬性,用 Object.defineProperty 為每個屬性添加 setter,getter 的方法。
vue的數據雙向綁定主要通過三個模塊完成:觀察者Observer、訂閱者Watcher、Compile解析模板指令。
(1)Observer監聽 model 的數據變化,如果有變動的,就通知訂閱者
(2)初始渲染頁面、為節點綁定函數:通過 Compile 掃描和解析每個節點的相關指令,將模板中的變量替換成數據,並根據初始數據渲染頁面視圖。並且將每個指令對應的節點綁定函數,一旦視圖交互,綁定的函數被觸發,然後觸發setter 方法,訂閱者就會收到通知。
(3)watcher 搭起了 observer 和 Compile 之間的通信橋梁,達到數據變化 —>視圖更新,視圖交互變化(input)—>數據 model 發生變更的雙向綁定效果。
var vm = new Vue({ data: {obj: { a: 1 }
}, created: function () {
console.log(this.obj);
}
});
打印Vue實例的data裏的某個數據的某個屬性,可以看到該屬性含有 setter、getter 方法,由此可以得知,每個屬性都被添加了setter、getter 方法。
1.1、思路分析
實現mvvm主要包含兩個方面,數據變化更新視圖,視圖變化更新數據:
view更新data通過事件監聽即,比如 input 標簽監聽 ‘input‘ 事件就可以實現。關鍵點在於 data 如何更新view,當數據改變,如何更新視圖的。重點是如何知道數據變了,而這可以由Observer實現,通過Object.defineProperty( )對屬性設置一個set函數,當數據改變了就會來觸發這個函數,然後只要將一些需要更新視圖的方法放在這裏面就可以實現data更新view了。
2、Observer 的實現
利用Obeject.defineProperty()來為每個屬性添加setter,getter 的方法實現監聽屬性變動。將需要observe的數據對象進行遞歸遍歷,包括子屬性對象的屬性,都加上 setter和getter,這樣的話,給這個對象的某個值賦值,就會觸發setter,那麽就能監聽到了數據變化。。示例代碼:
var data = { name: ‘kindeng‘ }; observe(data); data.name = ‘dmq‘; // 哈哈哈,監聽到值變化了 kindeng --> dmq function observe(data) { if (!data || typeof data !== ‘object‘) { return; } // 取出所有屬性遍歷 Object.keys(data).forEach(function (key) { defineReactive(data, key, data[key]); }); }; function defineReactive(data, key, val) { observe(val); // 監聽子屬性 Object.defineProperty(data, key, { enumerable: true, // 可枚舉 configurable: false, // 不能再define get: function () { return val; }, set: function (newVal) { console.log(‘哈哈哈,監聽到值變化了 ‘, val, ‘ --> ‘, newVal); val = newVal; } }); }
通過上面代碼就可以實現對每個屬性進行監聽。
3、JS實現簡單的雙向綁定
<body> <div id="app"> <input type="text" id="txt"> <p id="show"></p> </div> </body> <script type="text/javascript"> var obj = {} Object.defineProperty(obj, ‘txt‘, { get: function () { return obj }, set: function (newValue) { document.getElementById(‘txt‘).value = newValue document.getElementById(‘show‘).innerHTML = newValue } }) document.addEventListener(‘keyup‘, function (e) { obj.txt = e.target.value }) </script>
上面代碼中,首先 defineProperty 為每個屬性添加 getter、setter 方法,當數據發生改變, setter 方法被觸發,視圖也發生改變。setter 裏面的執行命令可以看做是一個訂閱者 Watcher,將視圖和數據連接起來了。最下面的代碼為節點綁定方法可以看做是Compile的作用,為指令節點綁定方法,當發生視圖交互時,函數被觸發,數據被改變,Watcher 收到通知,視圖也將發生改變。
Vue是如何實現雙向數據綁定的