JavaScript自定義事件

MableBradfi 8年前發布 | 6K 次閱讀 JavaScript開發 JavaScript

事件

技術一般水平有限,有什么錯的地方,望大家指正。

事件就是用戶和瀏覽器交互的一種途徑。假如一個用戶注冊的功能,我們在填寫完基本信息之后,點擊提交按鈕就可以實現注冊功能,要想完成這個功能所需要的就是點擊事件。我們預先定義好操作行為,在用戶點擊提交按鈕時就執行我們預先定好的行為,在本例中我們的代碼邏輯一般就是收集用戶填寫信息,驗證信息合法性,利用AJAX與服務器交互。

這個過程就好像我們平時封裝函數然后調用函數一樣,事件其實也就類似函數定義函數調用這樣的一個過程,只不過事件函數的調用是由用戶的一些操作來告知瀏覽器,讓瀏覽器在去調用函數的。

首先瀏覽器已經給我們提供了一列的事件,包括click,keydown等等,為什么還需要自定義事件呢?其實就是對我們的行為進行更準確的描述。以上面的用戶注冊為例我們可以定義一個名為saveMessage的事件,在點擊提交按鈕時觸發這個事件,好像看起來更加直觀一些,不過這看起來和普通的函數調用沒什么區別,仔細想了想函數調用和事件觸發的區別就是由我們自己執行的函數就是函數調用,不是由我們執行的函數就是事件觸發。看下面的代碼:

window.onload = function(){
    var demo = document.getElementById("demo");
    demo.onclick = handler;
    function handler(){
        console.log("aaa");
    }
}

在我們點擊按鈕的時候就會打印aaa,而且很明顯的可以看出函數并不是由我們調用的而是由瀏覽器來執行的,如果我們直接調用函數handler()一樣可以打印aaa但這是由我們調用的所以是函數調用。

自定義事件的作用

自定義事件就是我們按照瀏覽器對事件的機制來自定義的函數。自定義事件,可以對我們的處理函數帶來更好的說明,也可以為我們的插件帶來更好的處理流程。假如我們又一個這樣的需求:從服務器端拉取一組數據然后在HTML中顯示成列表,然后標識出第一條數據,假如我們利用一個現有的處理函數,我們可能會這樣來寫:

dataTable("url");
$("table").find("input[type='checkbox']:first").prop("checked",true);

這是不能達到我們目的的因為JS是單線程的而AJAX是異步的,當代碼$("table").find("input[type='checkbox']:first").prop("checked",true)執行的時候,我們需要的數據還沒有獲取到。我們去修改插件的內部實現顯然是不明智的,一個可以被人接受的插件必然是有合理的回調函數(或者自定義事件)的,假如現在有一個列表繪制成功的回調函數,我們就可以把這個回調函數看做是一個事件,我們可以對這個事件添加事件操作,定義好處理函數,然后在列表繪制成功時讓插件來執行這個處理函數。

自定義事件實現

我們模擬瀏覽器原生的事件來實現自定義事件(en:自定義事件名稱,fn:事件處理函數,addEvent:為DOM元素添加自定義事件,triggerEvent:觸發自定義事件):

window.onload = function(){
    var demo = document.getElementById("demo");
    demo.addEvent("test",function(){console.log("handler1")});
    demo.addEvent("test",function(){console.log("handler2")});
    demo.onclick = function(){
        this.triggerEvent("test");
    }
}
Element.prototype.addEvent = function(en,fn){
    this.pools = this.pools || {};
    if(en in this.pools){
        this.pools[en].push(fn);
    }else{
        this.pools[en] = [];
        this.pools[en].push(fn);
    }
}
Element.prototype.triggerEvent  = function(en){
    if(en in this.pools){
        var fns = this.pools[en];
        for(var i=0,il=fns.length;i<il;i++){
            fns[i]();
        }
    }else{
        return;
    }
}

由我們自己執行的函數是函數調用,非我們執行的函數我們可以叫做觸發事件,既然函數不是由我們調用的,那么調用者怎樣知道調用哪些函數就是一個問題了,所以就需要在添加事件函數和觸發事件函數之間加上一些約束了,那就是兩者之間有一個都能訪問到的事件池,添加事件時把事件及對應的處理函數放在這個池子里,當滿足觸發條件時就去池子里找到要觸發的事件,執行對應的處理函數,所以就有了我們上面的那一段代碼。

對同一個功能(事件)可能有很多個處理函數,所以我們就需要一個集合去存儲這些處理函數,這時我們應該反映出兩個方案JSON或者數組,JSON的結構是key:value,對于處理函數來說名字是沒有什么作用的所以我們用數組來保存處理函數,這組函數是處理什么功能的,所以我們還需要對這組處理函數由一個說明這時候就需要JSON了-->{eventName:[]}。

以簡化的BootStrap模態窗來演示自定義事件的作用:

window.onload = function(){
    var show = document.getElementById("show");
    var hide = document.getElementById("hide");
    var content = document.getElementById("content");
    show.onclick = function(){
        content.modal("show");
    }
    hide.onclick = function(){
        content.modal("hide");
    }
    content.addEvent("show",function(){alert("show before")});
    content.addEvent("shown",function(){
        document.getElementById("input").focus();
        alert("show after");
    });
} ;(function(ep){ ep.addEvent = function(en,fn){ this.pools = this.pools || {}; if(en in this.pools){ this.pools[en].push(fn); }else{ this.pools[en] = []; this.pools[en].push(fn); } } ep.triggerEvent = function(en){ if(en in this.pools){ var fns = this.pools[en]; for(var i=0,il=fns.length;i<il;i++){ fnsi; } }else{ return; } } ep.modal = function(t){ switch(t){ case "show": this.triggerEvent("show"); this.style.display = "block"; setTimeout(function(){this.triggerEvent("shown")}.bind(this),0);//該定時器主要是為了在視覺上先看見content,在彈出消息 break; case "hide": this.style.display = "none"; break; default: break; } }

}(Element.prototype)); </code></pre>

我們可以預先定義好在彈窗出現之前和出現之后的處理函數,當彈窗觸發對應事件的時候就執行對應的處理函數。

 

來自:http://www.cnblogs.com/shinhwazt/p/5989889.html

 

 本文由用戶 MableBradfi 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!