參考
剖析Vue原理&實現雙向綁定MVVM
javascript實現數據雙向綁定的三種方式
Vue實現雙向數據綁定的方式
Vue是如何實現雙向數據綁定的呢?答案是前端數據劫持。其通過Object.defineProperty()
方法,這個方法可以設置getter
和setter
函數,在setter函數中,就可以監聽到數據的變化,從而更新綁定的元素的值。
實現對象屬性變化綁定到UI
大概的思路是:
1. 確定綁定的數據,使用Object.defineProperty()對其數據變化進行監聽(對應defineGetAndSet)
2. 一旦數據發生改動,會觸發setter函數。因此在setter函數內要調用回調函數觸發綁定元素的更新。
3. 綁定元素的更新就是遍歷所有的綁定元素,通過綁定屬性的值確定函數的調用,並傳入修改後的值。(對應scan)
實現UI變化綁定到對象屬性
這個就比較簡單了,因爲UI的改變會觸發一些事件,比如keyup。通過監聽事件來實現數據的改變。而上面說了,數據的改變又會導致綁定其值的元素的UI改變。
實現
var data = {
value: 'hello world!'
}
var bindValue;
//確定綁定的元素
var bindelems = [document.getElementById('p'), document.getElementById('input')];
//修改綁定元素的值的方法
var command = {
text: function(str) {
this.innerHTML = str;
},
value: function(str) {
this.value = str;
}
};
//遍歷綁定元素修改其值
var scan = function() {
console.log('in scan');
for(var i = 0; i < bindelems.length; i++) {
var elem = bindelems[i];
console.log('elem',elem);
for(var j = 0; j < elem.attributes.length; j++) {
var attr = elem.attributes[j];
if(attr.nodeName.indexOf('q-')>=0) {
command[attr.nodeName.slice(2)].call(elem, data[attr.nodeValue]);
}
}
}
}
//設置劫持
var defineGetAndSet = function(obj, propname) {
Object.defineProperty(obj, propname, {
get: function() {
return bindValue;
},
set: function(value){
bindValue = value;
scan();
},
enumerable: true,
configurable: true
})
}
//一開始先初始化,使所有綁定的元素值爲初始值
scan();
//設置需要被劫持的元素
defineGetAndSet(data, 'value');
//監聽UI變化
bindelems[1].addEventListener('keyup', function(e) {
data.value = e.target.value;
});
setTimeout(function() {
data.value = 'change';
}, 1000);