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

好了,說了這么多,我們下面就一起來實現(xiàn)下吧。
二、正文
注:以下代碼皆編寫在observer.js文件中。
首先,當(dāng)數(shù)據(jù)變動,或者觸發(fā)某個事件時,我們需要與變動數(shù)據(jù)關(guān)聯(lián)一個自定義事件(自定義事件詳情見here),如果觸發(fā)某個事件,那么就執(zhí)行,如下:
綁定事件方法:
//let p = Observer.prototype
p.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.prototype
p.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);
}
});
}
}
}
觸發(fā)事件方法:
//let p = Observer.prototype
p.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();
}
});
}
}
其次,就是當(dāng)數(shù)據(jù)變動,觸發(fā)自身相關(guān)事件后,怎么一路冒泡到根結(jié)點的處理了。
怎么冒泡到根結(jié)點呢?
那就自身結(jié)點關(guān)聯(lián)父結(jié)點嘛,這樣不就可以追溯到根節(jié)點了么。
所以,我們在Observer.walk時,就將自己的父節(jié)點記錄即可,如下:
//let p = Observer.prototype
p.observe = function(key, data){
if(typeof data === 'object'){
let ob = new Observer(data);
//關(guān)聯(lián)父節(jié)點
ob._parent = {
key,
ob: this
};
}
}
最后,有了子父結(jié)點的依賴關(guān)系,那么冒泡方法就OK啦,如下:
//let p = Observer.prototype
p.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);
//判斷節(jié)點是否有父節(jié)點,若有,就向上傳遞事件
ob && ob.notify(eventName);
}
Perfect,具體代碼詳見github.
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
vue頁面設(shè)置滾動失敗的完美解決方案(scrollTop一直為0)
這篇文章主要介紹了vue頁面設(shè)置滾動失敗的解決方案(scrollTop一直為0),本文通過場景分析實例代碼相結(jié)合給大家介紹的非常詳細(xì),需要的朋友可以參考下2023-05-05
vue+element-ui JYAdmin后臺管理系統(tǒng)模板解析
這篇文章主要介紹了vue+element-ui JYAdmin后臺管理系統(tǒng)模板解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
vue中解決chrome瀏覽器自動播放音頻和MP3語音打包到線上的實現(xiàn)方法
這篇文章主要介紹了vue中解決chrome瀏覽器自動播放音頻和MP3語音打包到線上的實現(xiàn)方法,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-10-10

