由事件面試題引起的總結

一、描述下js裏面的【事件的三個階段】html

二、IE和W3C不一樣綁定事件解綁事件的方法有什麼區別,參數分別是什麼,以及事件對象e有什麼區別前端

三、【事件的代理/委託】的原理以及優缺點git

四、寫原生js【實現事件代理】,並要求兼容瀏覽器github

五、事件如何派發面試

六、JS事件模型與事件流介紹一下,事件代理用過嗎?自定義事件,事件廣播和分發瀏覽器

七、如何使用事件,以及IE和標準DOM事件模型之間存在的差異。dom

當面試時,問到這些問題時,問問本身是否能答的出來?函數

 

事件與事件流

  無論總結什麼、仍是複習什麼,概念從定義出發老是沒錯的。在《Javascript高級程序設計》中,是這麼說的"事件,就是文檔或瀏覽器窗口中發生的一些特定的交互瞬間",也就是說事件就是js與html之間的交互實現者。性能

  而事件流描述的是從頁面中接收事件的順序。而這兒就有兩種事件流,後面詳述。this

 

事件三個階段

能夠記住這個很是了不得的demo:https://wanliyuan.github.io/blog/testFunction.html (也是網上看到的)、很是清晰得展現了三個階段的過程。

三個階段分別是事件捕獲、處於目標階段、事件冒泡。

DOM2級事件規定的事件流就包括這個階段。首先先發生的是事件捕獲,爲截獲事件提供了機會。而後就是實際的目標接收到事件,最後就是冒泡階段,能夠在這個階段對事件做出相應。

 

五種事件處理程序

  先來知道什麼是事件處理程序。

<input type="button" id="btn" value="點擊" onclick="show(this)">
function show(obj){
    console.log(obj.value);
}

  這個show就是事件處理程序/事件偵聽器(-----響應事件的函數)。  

  一、HTML事件處理程序

  其實這種方式,相信前端的小夥伴們見得太多、也寫的太多了。它是在HTML中定義的事件處理程序包括了執行的具體動做,或者調用頁面別的地方定義的腳本,例以下面的代碼:

<input type="button" value="點擊" onclick="alert(11)">

<input type="button" value="點擊" onclick="show(this)">
function show(obj){
    console.log(obj.value);
}

 可是這種方式致使html與js的代碼耦合度過高,也是大多數開發人員擯棄的緣由。

  二、DOM0級事件處理程序

經過Javascript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。

        var btn = document.getElementById("btn");
        btn.onclick = function(){
            alert(this.id);
        }

刪除事件是:btn.onclick = null;

以這種方式添加的事件處理程序會在事件流的冒泡階段被處理,而且這時候的事件處理程序是在元素的做用域中進行,裏面的this就是當前元素。

  三、DOM2級事件處理程序

DOM2級事件是經過addEventListener和removeEventListener來處理指定和刪除事件處理程序的操做,接受三個參數(事件名、做爲事件處理程序的函數,布爾值)。布爾值爲true,表示在捕獲階段調用事件處理程序,如果false,則在冒泡階段處理。

        var btn = document.getElementById("myBtn");
        btn.addEventListener("click",function(){
            alert(this.id);
        },false);
        btn.addEventListener("click",function(){
            alert("Hello world");
        },false);

大多數狀況下,都是將事件處理程序添加到事件流的冒泡階段,這樣能夠最大限度地兼容各類瀏覽器。 經過removeEventListener刪除事件處理程序時,必須使用相同參數,主要是那個函數名,必須跟addEventListener同樣纔有效。

btn.addEventListener("click",show,false)
btn.removeEventListener("click",show,false)

  四、IE事件處理程序

IE事件處理程序跟DOM2的相似,有兩個方法attachEvent和detachEvent,不過這兒的參數只有兩個:事件處理程序名稱與事件處理程序函數。由於IE8以及更早的版本只支持事件冒泡,因此經過attachEvent添加的事件處理程序都會被添加到冒泡階段。

var btn = document.getElementById("myBtn");
        btn.attachEvent("onclick",function(){
            alert("clicked");
        });
     btn.attachEvent("onclick",function(){
            alert("Hello world");
        });

IE事件處理程序跟DOM2基本的區別:第一個參數是onclick、給同一個按鈕添加兩個不一樣的事件處理程序,是以相反的順序被觸發(Hello world -> clicked)

IE事件處理程序跟DOM0基本的區別事件處理程序的做用域是window(this==window)

經過detachEvent移除事件處理程序也同樣,第二個參數要傳跟attachEvent同樣的名兒。          

 五、跨瀏覽器處理程序

這兒的跨瀏覽器的處理程序,其實就是融合了DOM2級和IE的事件處理程序,以作到兼容大多數瀏覽器,並且只關注冒泡階段。

    var eventUtil = {
        addHandler:function(element,type,handler){
            if(element.addEventListener){
                element.addEventListener(type,handler,false);
            }else if(element.attachEvent){
                element.attachEvent("on"+type,handler);
            }else{
                element["on"+type] = handler;
            }
        },
        removeHandler:function(element,type,handler){
            if(element.removeEventListener){
                element.removeEventListener(type,handler,false);
            }else if(element.detachEvent){
                element.detachEvent("on"+type,handler);
            }else{
                element["on"+type] = null;
            }
        }
    }

  

三種事件對象

事件對象就是在觸發dom上事件時產生的,它包含全部與事件有關的信息,以下圖。全部瀏覽器都支持event對象,可是支持方式不一樣,全部纔有三種事件對象。

一、DOM中的事件對象

兼容DOM的瀏覽器都會將一個event對象傳入到事件處理程序中,不管是DOM0級仍是DOM2級,都會傳入event對象中。

 

二、IE中的事件對象

與訪問DOM中的event對象不一樣,訪問IE的event有幾種方式,取決於指定事件處理程序的方法。

如果DOM0級添加事件處理程序時,event對象做爲window對象的一個屬性存在。

        var btn = document.getElementById("myBtn");
        btn.onclick = function(){
            var event = window.event;
            alert(event.type);
        }

  

如果使用attachEvent添加,就會有event對象做爲參數被傳入事件處理程序函數。不過也能夠經過window對象來訪問event對象,跟DOM0級同樣。

        var btn = document.getElementById("myBtn");
        btn.attachEvent("click",function(event){
            alert(event.type);
        });

  

如果HTML指定事件處理程序,也還能夠經過event變量訪問event對象(跟DOM0級的事件模型同樣)

<input type="button" value="點擊" onclick="alert(event.type)">

  

三、跨瀏覽器的事件對象

var EventUtil = {
            addHandler:function(element,type,handler){
                //省略
            },
            getEvent: function (event) {
                return event ? event : window.event;
            },
            getTarget:function(event){
                return event.target || event.srcElement;
            },
            preventDefault:function(evnt){
                if(event.preventDefault){
                    event.preventDefault();
                }else{
                    event.returnValue = false;
                }
            },
            removeHandler:function(element,type,handler){
                //省略
            },
            stopPropagation:function(event) {
                if(event.stopPropagation){
                    event.stopPropagation;
                }else{
                    event.cancelBubble = true;
                }
            }
        }

  

事件代理/事件委託

  每一個函數都是對象,都會佔用內存;內存中的對象越多,性能越差。事先對指定全部事件處理程序而致使的dom訪問次數,會延遲整個頁面的交互就緒事件。因此就有了事件委託,對「事件處理程序過多」的解決方案是事件委託。

    var item1 = document.getElementById("goSomewhere");
    var item2 = document.getElementById("doSomething");
    var item3 = document.getElementById("sayHi");
    EventUtil.addHandler(item1,"click",function(event){
        location.href = "http://www.baidu.com";
    });
    EventUtil.addHandler(item2,"click",function(event){
        document.title = "test";
    });
    EventUtil.addHandler(item3,"click",function(event){
        alert("Hi");
    })

這個是給三個li添加事件處理程序,經過事件委託的以下:

     var list = document.getElementById("myLinks");
     EventUtil.addHandler(list,"click",function(event){
         event = EventUtil.getEvent(event);
         var target = EventUtil.getTarget(event);

         switch(target.id){
             case "goSomewhere":
                 location.href = "http://www.baidu.com";
                 break;
             case "doSomething":
                 document.title = "test";
                 break;
             case "sayHi":
                 alert("Hi");
                 break;
         }
     })

這個就只是添加了一個事件處理程序,用來處理頁面上發生的某種特定類型的事件,提高了總體性能,Live Demo。  

 

currentTarget與target

currentTarget是事件處理程序當前正在處理的那個元素,target是事件目標。

        var btn2 = document.getElementById("btn2");
        btn2.onclick = function(e){
            console.log(e.currentTarget==this); //true
            console.log(e.target==this);    //true
        }
        document.body.onclick = function(e){
            console.log(e.currentTarget==this);  //true
            console.log(e.target==this);  //false
            console.log(e.currentTarget===document.body);  //false
            console.log(this===document.body);  //false
            console.log(e.target===btn2);  //false
        }  
相關文章
相關標籤/搜索