假設有以下HTML代碼:html
<!DOCTYPE html> <html> <head> <title>Event</title> </head> <body> <div id="myDiv">Click me</div> </body> </html>
其DOM樹以下圖所示:
瀏覽器
若是點擊div元素,由於div是該DOM樹中層次最深的節點,那麼哪一個節點先接收事件?是由淺到深,仍是由深到淺?函數
事件流描述的是從頁面中接收事件的順序。
存在兩種事件流:事件冒泡(IE)和事件捕獲(Netscape)(這兩種事件流的事件傳播順序以下圖所示)
this
「DOM2級事件」規定的事件流包括三個階段:spa
仍以上面的例子爲例,單擊div元素的事件觸發順序以下圖所示:
code
事件是用戶或瀏覽器自身執行的某種動做(好比click、load、mouseover等)
事件處理程序(事件偵聽器)是響應某個事件的函數。
事件處理程序的名字以「on」開頭,如click事件的事件處理程序是onclick。htm
爲事件指定處理程序的方式有如下幾種:對象
可使用HTML爲元素指定事件處理程序,方法是:爲元素添加一個與事件處理程序同名的屬性,該屬性的值是可以執行的JS代碼或JS函數。blog
//直接定義JS代碼 <input type="button" value="點擊" onclick="alert('clicked')" /> //調用在頁面其餘地方定義的JS函數 <input type="button" value="點擊" onclick="showMessage()" />
以上代碼爲按鈕添加了鼠標單擊事件(click)的事件處理程序(onclick)。seo
注:這樣定義的事件處理程序在執行時,有權訪問全局做用域中的任何代碼
IE九、Firefox、Safari、Chrome和Opera支持DOM2級事件處理程序
var btn = document.getElementById("myBtn"); //爲按鈕指定onclick事件處理程序 btn.onclick = function(){ alert("Clicked"); }
注:
將事件處理程序屬性的值設置爲null便可刪除事件處理程序:
btn.onclick = null;
「DOM2級事件」定義了兩個方法來處理事件處理程序:
addEventListener(要處理的事件名,事件處理程序函數,布爾值)
var btn = document.getElementById("myBtn"); btn.addEventListener("click", function(){ alert(this.id); }, false);
注:
經過addEventListener()添加的事件處理程序只能經過removeEventListener()刪除,且刪除時傳入的參數必須與添加時傳入的參數相同。
可是經過addEventListener()添加的匿名函數沒法移除,最好是在其餘地方定義事件處理程序的函數,而後將該函數的名稱傳給第二個參數。
var btn = document.getElementById("myBtn"); //定義事件處理程序函數 var handler = function(){ alert(this.id); } btn.addEventListener("click", handler, false); btn.removeEventListener("click", handler, false);
支持IE事件處理程序的瀏覽器有IE和Opera
IE定義了兩個與DOM2級相似的方法:
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function(){ alert(this.id); });
注:
爲了保證跨瀏覽器的兼容性,咱們定義一個EventUtil對象,它包含addHandler()和removeHandler()兩個方法。
var EventUtil = { //addHandler()方法 addHandler:function(element, type, handler){ //DOM2級事件處理程序 if(element.addEventListener){ element.addEventListener(type, handler, false); } //IE事件處理程序 else if(element.attachEvent){ element.attachEvent("on"+type, handler); } //默認使用DOM0級事件處理程序 else{ element["on"+type]=handler; } }, //removeHandler()方法 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]=handler; } } };
觸發DOM上的某個事件時,會產生一個event事件對象,該對象包含着全部與事件有關的信息。
全部瀏覽器都支持event對象,但支持的方式不一樣。
兼容DOM(DOM0級和DOM2級)的瀏覽器將event對象傳入到事件處理程序中。
var btn = document.getElementById("myBtn"); btn.onclick = function(event){ alert(event.type); //"click" }; btn.addEventListener("click", function(event){ alert(event.type); //"click" }, false);
event對象的屬性和方法以下圖所示:
在上圖中,currentTarget的值始終等於this,而target只包含事件的實際目標。
若是直接將事件處理程序指定給了目標元素,則this === currentTarget === target
var btn = document.getElementById("myBtn"); btn.onclick = function(event){ alert(event.currentTarget === this); //true alert(event.target === this); //true } //上例中,點擊事件的目標是按鈕,而且把事件處理程序直接給了目標元素,因此三者的值相等
若是將事件處理程序沒有直接指定給目標元素,this === currentTarget !== target
document.body.onclick = function(event){ alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(target === document.getElementById("myBtn")); //true } //上例中,點擊世界的目標是按鈕,可是事件處理程序制定給了body元素,故三者並不相等。
在IE中,指定事件處理程序的方法不一樣,訪問event對象的方法也不一樣:
(1)使用DOM0級添加事件處理程序 —— event對象是window對象的一個屬性
var btn = document.getElementById("myBtn"); btn.onclick = function(){ var event = window.event; alert(event.type); //"click" }
(2)使用attachEvent()添加事件處理程序 —— event對象會被傳入事件處理程序函數中
var btn = document.getElementById("myBtn"); btn.attachEvent("onclick", function(event){ alert(event.type); //"click" });
(3)經過HTML特性指定事件處理程序 —— 經過event變量來訪問event對象
<input type="button" vaule="Click me" onclick="alert(event.type)"/>
雖然DOM和IE中的event對象不一樣,但基於它們之間的類似性,能夠實現跨瀏覽器的兼容性
var EventUntil = { //省略代碼 addHandler: function(element, type, handler){}, //獲取event對象 getEvent: function(event){ return event ? event : window.event; }, //獲取target getTarget: function(event){ return event.target||event.srcElement; }, //取消事件的默認行爲 preventDefault: function(event){ if(event.preventDefault){ event.preventDefault(); } else{ event.returnValue = false; } }, //取消冒泡 stopPropagation: function(event){ if(event.stopPropagation){ event.stopPropagation(); } else{ event.cancelBubble = true; } }, //省略代碼 removeHandler:function(element, type, handler){} };