由於對Vue.js很感興趣,並且平時工做的技術棧也是Vue.js,這幾個月花了些時間研究學習了一下Vue.js源碼,並作了總結與輸出。
文章的原地址:https://github.com/answershut...。
在學習過程當中,爲Vue加上了中文的註釋https://github.com/answershut...,但願能夠對其餘想學習Vue源碼的小夥伴有所幫助。
可能會有理解存在誤差的地方,歡迎提issue指出,共同窗習,共同進步。javascript
Vue.js是一款MVVM框架,上手快速簡單易用,經過響應式在修改數據的時候更新視圖。Vue.js的響應式原理依賴於Object.defineProperty,尤大大在Vue.js文檔中就已經提到過,這也是Vue.js不支持E8 以及更低版本瀏覽器的緣由。Vue經過設定對象屬性的 setter/getter 方法來監聽數據的變化,經過getter進行依賴收集,而每一個setter方法就是一個觀察者,在數據變動的時候通知訂閱者更新視圖。html
那麼Vue是如何將全部data下面的全部屬性變成可觀察的(observable)呢?vue
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)。java
那麼問題來了,須要對app._date.text操做纔會觸發set。爲了偷懶,咱們須要一種方便的方法經過app.text直接設置就能觸發set對視圖進行重繪。那麼就須要用到代理。react
咱們能夠在Vue的構造函數constructor中爲data執行一個代理proxy。這樣咱們就把data上面的屬性代理到了vm實例上。git
_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了。github
做者:染陌 數組
Email:answershuto@gmail.com or answershuto@126.com瀏覽器
Github: https://github.com/answershutoapp
Blog:http://answershuto.github.io/
知乎專欄:https://zhuanlan.zhihu.com/ranmo
掘金: https://juejin.im/user/58f87ae844d9040069ca7507
osChina:https://my.oschina.net/u/3161824/blog
轉載請註明出處,謝謝。
歡迎關注個人公衆號