在Vue中,使用了Object.defineProterty()這個函數來實現雙向綁定,這也就是為什么Vue不兼容IE8
1 響應式原理
讓我們先從相應式原理開始。我們可以通過Object.defineProterty()來自定義Object的getter和setter 從而達到我們的目的。
代碼如下
function observe(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*/ return val }, set:newVal=> { val = newVal; cb();/*訂閱者收到消息的回調*/ } })}class Vue { constructor(options) { this._data = options.data; observe(this._data, options.render) }}let app = new Vue({ el: '#app', data: { text: 'text', text2: 'text2' }, render(){ console.log("render"); }})通過observe函數對app.data上的每一個key和value都設定getter和setter。當value改變的時候觸發setter,就會觸發render這個函數。響應式的目的就達成,如果是視圖更新的話我們通過監聽dom的input事件來觸發數據更新
但是現在我們只有在改變vue._data.text的時候才會觸發他們的setter,但是我想偷懶,只改變vue.text就能觸發到setter怎么做呢?
我們使用代理的方法
_proxy.call(this, 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; } }) });}依賴收集
讓我們再來看看下面的代碼
new Vue({ template: `<div> <span>text1:</span> {{text1}} <span>text2:</span> {{text2}} <div>`, data: { text1: 'text1', text2: 'text2', text3: 'text3' }});當你的text3變化的時候,實際上text3并沒有被渲染,但是也會觸發一次render函數,這顯然是不對的。所以我們需要收集依賴。
我們只需要在初始化的時候渲染一遍,那所有渲染所依賴的數據都會被觸發getter,這時候我們只要把這個數據放到一個列表里就好啦!
我們先來認識一下Dep(dependencies)這個類,下圖是一個最簡單的Dep類。我們可以把他理解為發布者(這點很重要?。。?br />
class Dep { constructor () { this.subs = []; } addSub (sub: Watcher) { this.subs.push(sub) } removeSub (sub: Watcher) { remove(this.subs, sub) } /*Github:https://github.com/answershuto*/ notify () { // stabilize the subscriber list first const subs = this.subs.slice() for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } }}function remove (arr, item) { if (arr.length) { const index = arr.indexOf(item) if (index > -1) { return arr.splice(index, 1) }}
新聞熱點
疑難解答
圖片精選