一、描述下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中定義的事件處理程序包括了執行的具體動做,或者調用頁面別的地方定義的腳本,例以下面的代碼:
<input type="button" value="點擊" onclick="alert(11)"> <input type="button" value="點擊" onclick="show(this)"> function show(obj){ console.log(obj.value); }
可是這種方式致使html與js的代碼耦合度過高,也是大多數開發人員擯棄的緣由。
經過Javascript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。
var btn = document.getElementById("btn"); btn.onclick = function(){ alert(this.id); }
刪除事件是:btn.onclick = null;
以這種方式添加的事件處理程序會在事件流的冒泡階段被處理,而且這時候的事件處理程序是在元素的做用域中進行,裏面的this就是當前元素。
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事件處理程序跟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是事件目標。
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 }