一、前言
在"模擬Vue之數據驅動4"中,我們實現了push、pop等數組變異方法。
但是,在隨筆末尾我們提到,當pop、sort這些方法觸發后,該怎么辦呢?因為其實,它們并沒有往數組中新增屬性呢。
而且,當數據改動后,如果我們在變動數據處,就立即更改數據也未免性能不夠,此時,走讀Vue源碼,發現他用了一個很巧妙的方法,就是職責鏈模式。當某個數據有所變動時,它會向上傳遞,通俗點就是冒泡至根結點,這樣我們也可以在自己代碼中使用事件代理咯,哇卡哇卡。
示意圖如下所示:

好了,說了這么多,我們下面就一起來實現下吧。
二、正文
注:以下代碼皆編寫在observer.js文件中。
首先,當數據變動,或者觸發某個事件時,我們需要與變動數據關聯一個自定義事件(自定義事件詳情見here),如果觸發某個事件,那么就執行,如下:
綁定事件方法:
//let p = Observer.prototypep.on = function(eventName, fn){ let listener = this.listener = this.listener || []; if(typeof eventName === 'string' && typeof fn === 'function'){ if(!listener[eventName]){ listener[eventName] = [fn]; }else{ listener[eventName].push(fn); } } }取消事件方法:
//let p = Observer.prototypep.off = function(eventName, fn){ let listener = this.listener = this.listener || []; let actionArray = listener[eventName]; if(typeof eventName === 'string' && Array.isArray(actionArray)){ if(typeof fn === 'function'){ actionArray.forEach( (func, i, arr) => { if(func === fn){ arr.splice(i,1); } }); } }}觸發事件方法:
//let p = Observer.prototypep.emit = function(eventName){ let listener = this.listener = this.listener || []; let actionArray = listener[eventName]; if(Array.isArray(actionArray)){ actionArray.forEach( func => { if(typeof func === 'function'){ func(); } }); }}其次,就是當數據變動,觸發自身相關事件后,怎么一路冒泡到根結點的處理了。
怎么冒泡到根結點呢?
那就自身結點關聯父結點嘛,這樣不就可以追溯到根節點了么。
所以,我們在Observer.walk時,就將自己的父節點記錄即可,如下:
//let p = Observer.prototypep.observe = function(key, data){ if(typeof data === 'object'){ let ob = new Observer(data); //關聯父節點 ob._parent = { key, ob: this }; } }最后,有了子父結點的依賴關系,那么冒泡方法就OK啦,如下:
//let p = Observer.prototypep.notify = function(eventName){ let ob = this._parent && this._parent.ob; let key = ob && this._parent.key || 'root'; console.log('parent--'+key+' event--'+eventName); this.emit(eventName); //判斷節點是否有父節點,若有,就向上傳遞事件 ob && ob.notify(eventName); }Perfect,具體代碼詳見github.
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持武林網。
新聞熱點
疑難解答