扯扯javascript之自定義事件

如果您看到這篇文章 說明您知道js中事件這個東西,js中操作少不了事件的參與,小到click mouse等事件,大到面向對象處理事件。

白了,js就是一個處理事件的東東。。只是作用環境不同或者不明顯而已。向上追溯祖宗八代 肯定能找到相關事件。。只是那個時代的js不像現在這麼多功能,

在加上各個瀏覽器大哥之間慪氣,可苦了我們這幫做js的小弟了。暫定一下 咱回來,別跑偏了。。。

自定義事件也是事件一種 跟函數綁定等一樣,都是爲了更完美的實現我們想要實現功能,達到code期望並且讓代碼讀起來優美有含量。

這裏所說的javascript自定義事件分爲兩種,一種是DOM自定義事件,另一種是js自定義事件。不過無論哪種自定義事件都是基於網上通常所說的觀察者模式理論來實現。

所謂觀察者模式,就是你作爲觀察者不去理會被觀察者到底發生了什麼,不過只要被觀察者一旦出事了,你就要相應的做出決策,就像不去理會數據庫裏面的數據到底爲什麼更新了一樣。那麼爲什麼這樣做呢。。。

好,我來回答你!

難不成你希望你寫一個程序功能要考慮周全未來將要發生所有不可預測事情嗎?

難不成你希望你封裝了一段功能之後有人在裏面亂七八糟的添加新功能嗎?

就像你每天起牀後都要考慮應該不應該起牀呢?

good 貌似你服了這個反問。。。

怎麼沒人管管我呢 老跑偏。。

言歸正傳,先從DOM層的自定義事件說起,DOM自定義事件肯定是有別於瀏覽器自定義的事件,比如:click,mouse,key等事件,可以通過自定義進行添加,調用以及刪除。

舉個栗子吧:

前段時間我東家(產品)要求實現一個功能就是按下一個按鈕去判斷按下時間是否超過1秒才鬆開來處理兩個不同事件。我心想這簡單啊,去判斷mouse事件的間隔時間不就完事了,於是咔嚓咔嚓寫完了,東家一測很滿意,然後說,

我還想知道用戶到底按了多久,於是乎我就又咔嚓咔嚓咔嚓實現了,期間東家還過來說另外好幾個地方都需要這功能,做完後幫他們支持一下。。

我立馬爽快的答應了東家,心想不就是封裝一個小組件麼。回頭一想這個組件裏面處理事情不同,點擊事件需求也不一定相同,關鍵的是我爲啥還得多做那麼多工作呢(不是工作態度問題哦。。)。。

突然 腦門一熱,弄個自定義事件得了,誰不會用click事件呢?於是一個我的longPress事件橫空出世了。主要代碼如下,看完代碼再說理論

function myLongPress(target, timeInterval) {

var timer;

var myEvt = document.createEvent('Event');

myEvt .initEvent('longPress', true, true);

target.addEventListener('mousedown', function() {

timer = Date.now();

}, false);

target.addEventListener('mouseup', function() {

if(Date.now() - timer > timeInterval) {

myEvt .interval= Date.now() - timer;

target.dispatchEvent(myEvt );

}

}, false);

}

myLongPress($('ni'), 2000);

$('ni').addEventListener('longPress', function(e) {

console.log('您已經摁下了 ' + e.duration + '毫秒了,走神了麼.');
}, false);

主要根據dom中增加自定義事件的一個組合來實現我們功能(createEvent,initEvent,dispatchEvent),createEvent首先聲明我要創建一個新的dom事件,於是initEvent接到通知開始定義了一個longPress事件,並且注入三個參數分別爲 事件類型,是否冒泡,是否可取消。定義完之後我們就可以隨意定義我們的longPress事件如何觸發的了。我們在這個函數中傳入兩個值一個是操作元素,另一個是判斷間隔自定義時間(就像我東家提的1秒),用我們的操作元素先去監聽鼠標按下事件並且記錄下按下那一刻的具體時間,然後讓我們元素去監聽鼠標擡起來時候的事件,這個時候我們的longPress事件才真正的定義完成,也就是說用戶target做完這兩個事件後自定義事件纔會觸發,就像click一樣需要按下擡起來鼠標。於是我們去判斷前兩個事件間隔時間並將間隔時間作爲一個事件屬性供小夥伴們去調用,然後target開始去執行我們的自定義事件去了 也就是dispatchEvent。至此我們的自定義事件over了。怎麼樣簡單不,你還可以隨意的增加實例事件哦。

其實這就叫dom的自定義事件,怎麼樣 實現起來很簡單吧,只是js中術語太多了 讓我們以爲多高深似的。。。

再說說另一種情況那就是js自定義事件

通常我們說的mvc結構層的view結構就是出於觀察者身份,它只管檢測數據有沒有變化 如果變化我就要做什麼,面向對象也有一個原則就是每個類都把重點放到一個功能上面儘可能降低耦合度,自定義事件使得觀察者跟對象模塊以及對象模塊和對象模塊之間劃分了界限,大大提高了對象的複用性和程序的可維護性。自定義事件的實現原理也挺簡單,平時我們定義的各種click事件其實就可以想象成把各種click事件放到一個{}裏面,用到這個{}裏面哪個事件時候哪個事件就出來工作,確定不用了再可以刪除。同理我們可以想象一下我們如果自定義這種事件不也同樣能達到這個效果麼。於是開始動手:

首先我們定義個函數,並將之前說的那個{}至於裏面作爲公用屬性。

var definedEvent=function(){

this.events={};

}

之後我們開始定義事件並且定義事件觸發和刪除機制:

definedEvent.prototype={

constructor:definedEvent,

addEvent:function(type,event){

if(typeof this.events[type]=='undefined'){
               
this.events[type]=new Array();
            }
            this.
events[type].push(event);

},

removeEvent:function(type,event){

if(this.events[type] instanceof Array){

var events=this.events[type];

for(var i=0,len=events.length;i<len;i++){

if(events[i]==event){

events.splice(i,1);

break;

}

}

}

},

fire:function(params){

if(!params.target){

params.target=this;

}

if(this.events[params.type] instanceof Array){

var events=this.events[params.type];

for(var i=0,len=events.length;i<len;i++){

events[i](params);

}

}

}

}

應用如下:

var a=new definedEvent();

function here(param){

alert("這是我自定義的方法"+param);

}

a.addEvent("myEvent",here)

a.fire({type:"myEvent",param:"myEvent"});

a.removeEvent('myEvent',here)

我們在函數基礎上利用原型去增加其方法,首先在addEvent中增加並定義一個事件傳兩個參數一個是自定義事件名稱type另一個是自定義具體事件event並且將其放到events這個公有屬性中存儲起來,然後在fire中進行引用,fire中傳入一個參數params,params中的type是必須的 其type必須跟addEvent中的type是一致的才能觸發,並且我們還可以在fire事件中params傳參數從而達到觸發事件目的。最後的最後如果我們想消除該自定義事件就直接removeEvent就ok了。

說到這裏爲止可能還會有人說 我幹嘛自定義事件啊,我直接調用一個函數不就得了。。。,ok,我脾氣好 不爭辯,用事實舉個栗子來說一下:

通常我們做前端都不可避免會遇到自定義彈出框功能,而且自定義的彈出框要根據業務去顯示內容以及大小按鈕等。一般來說我們都會將其封裝爲一個類,code人員只需要調用傳參就可以了。但是實際業務中 很多都需要在彈出框下面遮住一層面紗防止在彈出框之外進行二次操作。 當然還有可能是打開或者關閉彈框時候實現其他功能。咱就拿這個最簡單的舉栗子!

那麼這時候我們就有兩個彈出框之外的事情去處理了,一個是打開彈出框時候要出現面紗在彈出框與頁面之間,另一個是在點擊關閉彈出框時候幹掉面紗。這兩個事件不可能寫到我們已經寫好的"類"中,那樣會糟蹋了我們的類,並且以後維護起來特費勁。

打開時候好說,可以在調用彈出框類時候同步實現出現面紗,但是關閉時候呢?關閉按鈕是在彈出框中的,並且關閉按鈕默認功能只是將彈出框關閉。如何實現我們想要的幹掉面紗呢。這個時候自定義事件就派上用場了!!!看代碼

首先簡單定義我們的彈出框類:

var myPop=function(id){

definedEvent.call(this);

this.id=id;

$(id).children[0].οnclick=function(){

that.close();//關閉按鈕操作

}

}

myPop.prototype=new definedEvent();

myPop.prototype.show=function(){

/*彈出彈出框*/

}

myPop.prototype.close=function(){

/*關閉彈出框*/

this.fire('myClose')//觸發自定義事件

}

function openPop(){

var pop=new myPop("id");

pop.addEvent("myClose",function(){

/*關閉面紗*/

})

pop.show()

}

上面代碼我們用我們的彈出的類去繼承自定義事件類(前面文章頁說過了this以及繼承的東東了)從而將this指向了myPop,同時myPop中也包含自定義事件的方法。這樣一來我們就可以在我們的類中觸發自定義事件,而自定義事件完全獨立於我們的類之外,絲毫沒有污染到原對象,這樣就達到了我們代碼可維護性,並且我們的彈出類是純潔的了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章