javascript自定義事件原理

weixin_33763244發表於2017-03-21

我們都知道,滑鼠點選click,觸屏的touch等事件,可以觸發相應的事件處理程式,也可以為這些事件新增事件處理程式,實際開發過程中可供我們使用的事件很少,click、doubleclick,mouseover、mousemove….等等這些。但當我們的程式越來越複雜的時候,光靠這些最底層的監聽似乎已近不能滿足我們的需求了。我們就需要我們自己去定義事件(其實就是我們寫的函式),尤其是元件開發過程中,用的尤為多。

既然是事件,就要有事件的特性。我們要能為這個事件新增監聽程式,這個事件觸發時,監聽程式也一定要觸發才行。原理跟底層的事件類似。只不過,需要我們自己處理這些。

比如我們寫了一個彈窗元件Box,他有彈出顯示的方法show,還有關閉的方法close等。

可能有確定按鈕、取消按鈕等操作。隨著產品或專案越複雜,被新增到這些確定或取消的操作也會越來越多。怎麼辦?一種是最原始的監聽這些按鈕的click事件,然後的寫不同的回撥。但是用回撥的方式,有個弊端,當專案需求改變的時候,要往這個按鈕上再另加個回撥的時候,就要改原先的程式碼,要是以後再來一次,又要改。維護成本相當大。

我們不妨換個思路,把這個‘確定’或‘取消’想成像click這樣的事件,當‘確定‘這個事件發生時其相應的一系列事件都會發生。就可以很好的解決這個問題。

基本原理:事件佇列,即將監聽程式存到一個陣列中,再自定函式執行時,將新增監聽陣列中每個函式執行一遍。

定義一個物件專門用於儲存自定義事件,定義一個方法用於註冊監聽,還有一個方法需要我們主動觸發這個註冊的監聽程式(因為不像click等事件可以被瀏覽器監聽捕獲,瀏覽器無法識別我們自己定義的東西)。

程式碼如下:

//定義一個Box類
function Box(){
    //other code
    this.handlers = {};//儲存事件的物件 
}
Box.prototype = {
    constructor: Box,
    //顯示方法
    show: function (){
        //code
        //this.fire('show');
    },
    //關閉方法
    close: function (){
         //code
        //this.fire('close');
    },
    //監聽方法,模擬addEventListener,其中type為事件函式,handler為需要觸發的函式。
    addListener: function (type,handler){    
        if (typeof this.handlers[type] == 'undefined')this.handlers[type] = []; 
        this.handlers[type].push(handler);//將要觸發的函式壓入事件函式命名的陣列中
    },
    //手動觸發方法
    fire: function (type){
        if ( this.handlers[type] instanceof Array ){
            var handlers = this.handlers[type];
            //遍歷事件函式監聽的程式,依次執行
            for (var i=0;i<handlers.length;i++){
               handlers[i]();
            }
        }
    },
    //事件解綁
    removeListener: function (type,handler){
        if (!this.handlers[type]) return;
        var handlers = this.handlers[type];
        if (handler == undefined){
          handlers.length = 0;//不傳某個具體函式時,解綁所有
        }else if( handlers.length ){    
            for ( var i=0;i<handlers.length;i++ ){
                if ( handlers[i] == handler ){
                                //解綁單個
                    this.handlers[type].splice(i,1);
                }
            }
        }
    }
}

剩下就是在需要的的時候新增註冊監聽了,比如

var box = new Box();
function listenShow1(){
    console.log(11);
}
function listenShow2(){
    console.log(22);
}
box.addListener('show',listenShow1);
box.addListener('show',listenShow2);
box.show();

當show方法執行,在外部或者show方法內部執行,這個可能根據實際具體專案或這具體情況來確定。

當然以上只是基本原理,可能沒有特別考慮更為複雜或具體的實際情況。比如解綁是隻想解綁某一類,像jQuery那樣,在事件身上加名稱空間,解綁該名稱空間上的所有函式。但是自定義事件的基本原理就是如上描繪的那樣!

相關文章