Vue.js資料繫結原理

染陌同學發表於2017-08-21

寫在前面

因為對Vue.js很感興趣,而且平時工作的技術棧也是Vue.js,這幾個月花了些時間研究學習了一下Vue.js原始碼,並做了總結與輸出。
文章的原地址:github.com/answershuto…
在學習過程中,為Vue加上了中文的註釋github.com/answershuto…,希望可以對其他想學習Vue原始碼的小夥伴有所幫助。
可能會有理解存在偏差的地方,歡迎提issue指出,共同學習,共同進步。

關於Vue.js

Vue.js是一款MVVM框架,上手快速簡單易用,通過資料繫結在修改資料的時候更新檢視。Vue.js的資料繫結原理依賴於Object.defineProperty,尤大大在Vue.js文件中就已經提到過,這也是Vue.js不支援E8 以及更低版本瀏覽器的原因。Vue通過設定物件屬性的 setter/getter 方法來監聽資料的變化,通過getter進行依賴收集,而每個setter方法就是一個觀察者,在資料變更的時候通知訂閱者更新檢視。

將資料data變成可觀察(observable)的

那麼Vue是如何將所有data下面的所有屬性變成可觀察的(observable)呢?

function observer(value) {
    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: ()=>{
            /*....依賴收集等....*/
        },
        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._date.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了。.js

關於

作者:染陌

Email:answershuto@gmail.com or answershuto@126.com

Github: github.com/answershuto

Blog:answershuto.github.io/

知乎專欄:zhuanlan.zhihu.com/ranmo

掘金: juejin.im/user/58f87a…

osChina:my.oschina.net/u/3161824/b…

轉載請註明出處,謝謝。

歡迎關注我的公眾號

img
img

相關文章