歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> JavaScript自定義事件

JavaScript自定義事件

日期:2017/3/1 9:10:50   编辑:Linux編程

事件

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

  事件就是用戶和浏覽器交互的一種途徑。假如一個用戶注冊的功能,我們在填寫完基本信息之後,點擊提交按鈕就可以實現注冊功能,要想完成這個功能所需要的就是點擊事件。我們預先定義好操作行為,在用戶點擊提交按鈕時就執行我們預先定好的行為,在本例中我們的代碼邏輯一般就是收集用戶填寫信息,驗證信息合法性,利用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++){
                fns[i]();
            }
        }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));

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

JavaScript權威指南(第6版) PDF中文版+英文版+源代碼 下載地址見 http://www.linuxidc.com/Linux/2013-10/91056.htm

Copyright © Linux教程網 All Rights Reserved