關於Vue.js
Vue.js是一款MVVM框架,上手快速簡單易用,通過響應式在修改數據的時候更新視圖。Vue.js的響應式原理依賴於Object.defineProperty,尤大大在Vue.js文檔中就已經提到過,這也是Vue.js不支持IE8 以及更低版本瀏覽器的原因。Vue通過設定對象屬性的 setter/getter 方法來監聽數據的變化,通過getter進行依賴收集,而每個setter方法就是一個觀察者,在數據變更的時候通知訂閱者更新視圖。
將數據data變成可觀察(observable)的
那麼Vue是如何將所有data下面的所有屬性變成可觀察的(observable)呢?
function observer(value, cb) {
Object.keys(value).forEach((key) => defineReactive(value, key, value[key] , cb))
}
function defineReactive (obj, key, val, cb) {
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: ()=>{
/*....依賴收集等....*/
/*Github:https://github.com/answershuto*/
},
set:newVal=> {
cb();/*訂閱者收到消息的回調*/
}
})
}
class Vue {
constructor(options) {
this._data = options.data;
observer(this._data, options.render)
}
}
let app = new Vue({
el: '#app',
data: {
text: 'text',
text2: 'text2'
},
render(){
console.log("render");
}
})
爲了便於理解,首先考慮一種最簡單的情況,不考慮數組等情況,代碼如上所示。在initData中會調用observe這個函數將Vue的數據設置成observable的。當_data數據發生改變的時候就會觸發set,對訂閱者進行回調(在這裏是render)。
那麼問題來了,需要對app._data.text操作纔會觸發set。爲了偷懶,我們需要一種方便的方法通過app.text直接設置就能觸發set對視圖進行重繪。那麼就需要用到代理。
代理
我們可以在Vue的構造函數constructor中爲data執行一個代理proxy。這樣我們就把data上面的屬性代理到了vm實例上。
_proxy(options.data);/*構造函數中*/
/*代理*/
function _proxy (data) {
const that = this;
Object.keys(data).forEach(key => {
Object.defineProperty(that, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return that._data[key];
},
set: function proxySetter (val) {
that._data[key] = val;
}
})
});
}
我們就可以用app.text代替app._data.text了。