咱們知道JavaScript與HTML之間的交互是經過事件實現的。事件最先是在IE3和Netscape Navigator 2中出現的,當時是做爲分擔服務器運算負載的一種手段。 通俗地理解,事件就是用戶或瀏覽器自身執行的某種操做。而事件處理程序即爲響應某個事件的函數。抽出主幹,即事件處理程序爲函數。 咱們又把事件處理程序稱爲事件偵聽器。 事件處理程序是以"on"開頭的,所以對於事件on的時間處理程序即爲onclick。時間處理程序在JavaScript中大體有五種,下面會根據這五種不一樣的時間處理程序分爲5部分來介紹。html
什麼使HTML事件處理程序呢?顯然,經過名字就能夠猜到,它是卸載HTML中的函數(事件處理程序)。初學者大多用到的事件處理程序即爲HTML事件處理程序。下面舉例:前端
例1:chrome
<button onclick="alert('success')">點我</button>
這條代碼即爲事件處理程序,點擊button後,會彈出彈框,顯示success。瀏覽器
特色:HTML事件處理程序中Javascript代碼做爲了onclick特性的值,所以,咱們不能在JavaScript代碼中使用未經轉義的HTML語法字符,如&(和號)、""(雙引號)、<(小於號)、>(大於號)等等。因此這個例子中字符串我使用了單引號而沒有使用雙引號。看下面在JavaScript代碼中使用了未經轉義的HTML語法字符。服務器
例2:dom
<button onclick="alert("success")">點我</button>
這時,我在success外使用了HTML語法字符""(雙引號),這時不會彈出窗口,而是報錯語法錯誤。可是我若是仍是但願使用雙引號呢? 這時就要用"實體來代替HTML中的語法字符。以下例所示:函數
例3:this
<button onclick="alert("success")">點我</button> <!-- 正常彈出窗口-->
這個例子中咱們在JavaScript代碼中使用了HTML實體而沒有使用HTML語法字符,這時就不會報錯了。spa
例4:code
<button onclick="show()">點我</button> <!-- 正常彈出窗口--> <script> function show(){ alert("success"); } </script>
這個例子中咱們調用函數,而把函數定義放在了script中,這樣也是能夠的。由於:事件處理程序中的代碼在執行時,有權訪問到全局做用域中的任何代碼。這句話怎麼理解呢? 實際上,咱們能夠在chrome中觀察button標籤的做用域鏈。以下所示:
接下來咱們再看看script所在的做用域,以下圖所示:
能夠看到script標籤就在全局做用域。
也就是說目前button中的HTML事件處理函數在做用域鏈的最前端,而Script在全局做用域,因此「事件處理程序中的代碼在執行時,有權訪問到全局做用域中的任何代碼。」這句話就不難理解了。
例5:
<button onclick="alert(event.type)">點我</button>
這時瀏覽器彈出窗口顯示:click。這個例子是什麼意思呢?注意到我並無在event.type外加單引號,說明這並非字符串。實際上,event是局部對象--在觸發DOM上的某個事件時,會產生一個事件對象event,這個對象包含着全部與事件有關的信息。而這裏是彈出了對象了類型,即爲click。
HTML事件處理程序的三個缺點(重點):
1. 時差問題。 由於用戶可能在HTML元素一出現就開始觸發相應事件,可是有可能該事件的腳本(如例4中show()函數的函數定義在script中)尚未加載完成,此時不具有執行條件,故報錯。
解決方法:將HTML事件處理程序封裝在一個try-catch塊中,以便錯誤不會浮出水面。
<input type="button" value="click me" onclick="try{show();}catch(ex){}">
2.這樣擴展事件實例程序的做用域鏈在不一樣的瀏覽器中會致使不一樣的結果(例4中我是在chrome中查看的做用域鏈,其餘瀏覽器不必定是這樣的,請注意)。不一樣JavaScript引擎遵循的標識符解析規則略有差別,頗有可能會在訪問非限定對象成員時出錯。
3.HTML和JavaScript代碼緊密耦合。 結果是:若是要更換事件處理程序,就必須改動兩個地方--HTML代碼和JavaScript代碼。
那麼怎麼解決上面的問題呢? DOM0級事件處理程序是一個不錯的選擇!
DOM0級事件處理程序用的也很是廣泛。之因此成爲DOM0級,我認爲是當時尚未出DOM標準,而IE和Netscape Navigator二者使用的時間處理程序(不知是否合理,望批評指正)。 總之,咱們先看看下面的例子吧。
例6:
<button id="button">點我</button> <script> var button=document.getElementById("button"); button.onclick=function(){ alert("clicked"); } </script>
即咱們先在script中取得元素的引用,而後再將一個函數賦值給onclick事件處理程序。 以前介紹過,事件處理程序即爲函數,而button.onclick這種形式即函數做爲了對象的方法。那麼對象的方法即事件處理程序是在元素(對象)的做用域中運行而非在全局做用域中運行的,由於方法是屬於對象的。(注意:例4中事件處理程序是在全局做用域中運行的)。 若是這個函數中存在this關鍵字,那麼this就會指向這個對象。下面咱們在瀏覽器中證實事件處理程序是在元素的做用域中運行。
咱們看到alert("clicked");確實是在button中運行的。
咱們還能夠經過下面的方式刪除經過DOM0級方法指定的事件處理程序。
button.onclick=null;
經過上面的分析咱們能夠知道DOM0級事件處理程序是很是不錯的,它解決了HTML事件處理程序的三個缺點:時差問題、做用域鏈致使的不一樣瀏覽器表現不一致問題和HTML和JavaScript緊密耦合問題。
可是,DOM0級事件處理程序並非完美的,它一樣有兩個缺點:
對於第二個問題後面會講到,第一個問題舉例以下:
<button id="button">點我</button> <script> var button=document.getElementById("button"); button.onclick=function(){ alert("clicked"); } button.onclick=function(){ alert("again"); }
雖然我對同一個元素設置了兩個事件處理程序,可是最終的結果是:只有第二個事件有效(覆蓋了第一個事件)。固然,人類是聰明的動物,DOM2級事件很好的解決了這個問題!
DOM2級事件處理程序定義了兩個方法:
在博文的開頭我就提到了事件處理程序即事件偵聽器。這兩個方法都接收三個參數:
下面經過兩個例子加深理解:
例7:
<button id="button">點我</button> <script> var button=document.getElementById("button"); button.addEventListener("click",function(){ alert(this.id); },false); button.addEventListener("click",function(){ alert("another event"); },false); </script>
結果:第一次彈出窗口:button。
第二次彈出窗口:another event。
結論:經過DOM2級事件處理程序,咱們能夠爲同一個元素添加兩個或更多的事件。事件根據順序依次觸發。且this一樣指向當前元素,故函數在元素的做用域中執行。
this分析:和前面的DOM0級事件處理程序同樣,這裏的addEventListener一樣也能夠看做對象的方法,不一樣之初在於,DOM0級的方法須要另一個函數來賦值,而這裏的方法是DOM2級規範預約義的。
removeEventListener()這個刪除事件處理程序的方法值得注意的是:使用addEventListener()來添加的事件處理程序只能經過它來移除,且須要傳入相同的參數。
例8:
<button id="button">點我</button> <script> var button=document.getElementById("button"); button.addEventListener("click",function(){ alert(this.id); },false); button.removeEventListener("click",function(){ alert("another event"); },false);
上述代碼貌似能夠移除click的事件處理程序,可是經過實驗證實是不能夠的,緣由是:事件處理程序爲匿名函數時沒法移除。看下面的成功移除的例子:
例9:
<button id="button">點我</button> <script> var button=document.getElementById("button"); function handler(){ alert(this.id); } button.addEventListener("click",handler,false); button.removeEventListener("click",handler,false); </script>
成功移除!
注意:1.傳入方法的handler沒有(),是由於這裏都只是定義函數,而不是調用,須要注意。
2.這兩個方法的第三個參數都是false,即事件處理程序添加到冒泡階段。通常不使用true,由於低版本的IE不支持捕獲階段。
DOM2級事件處理程序成功地解決了前面全部事件處理程序的問題,堪稱perfect!!!! 然而老是特立獨行的IE瀏覽器又有新花樣,它也有本身的一套事件處理程序,下面咱們就來看看吧。
IE事件處理程序中有相似與DOM2級事件處理程序的兩個方法:
它們都接收兩個參數:
之因此沒有和DOM2級事件處理程序中相似的第三個參數,是由於IE8及更早版本只支持冒泡事件流。
注意:
1.IE事件處理程序中attachEvent()的事件處理程序的做用域和DOM0與DOM2不一樣,她的做用域是在全局做用域中。所以,不一樣於DOM0和DOM2中this指向元素,IE中的this指向window。
2.一樣,咱們可使用attachEvent()來給同一個元素添加多個事件處理程序。可是與DOM2不一樣,事件觸發的順序不是添加的順序而是添加順序的相反順序。
3.一樣地,經過attachEvent()添加的事件處理程序必須經過detachEvent()方法移除,一樣的,不能使用匿名函數。
4.支持IE事件處理程序的瀏覽器不僅有IE瀏覽器,還有Opera瀏覽器。
實際上,這一部分視爲了跨瀏覽器使用,將前面的幾部分結合起來就能夠了。
這一部分須要建立兩個方法:
這兩個方法接收相同的三個參數:
這兩個方法的構造狀況以下:
var EventUtil={ addHandler:function(element,type,handler){ if(element.addEventListener){ element.addEventListener(type,handler,false);//注意:這裏默認使用了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);//注意:這裏默認使用了false(冒泡) }else if(element.detachEvent){ element.detachEvent("on"+type,handler); }else{ element["on"+type]=null; } } };
即先判斷DOM2級事件處理程序,再判斷IE事件處理程序,最後使用DOM0級事件處理程序。
例10:經過這個例子來使用上面構造的方法。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>跨瀏覽器事件處理程序</title> </head> <body> <button id="button">點我</button> <script> var EventUtil={ addHandler:function(element,type,handler){ if(element.addEventListener){ element.addEventListener(type,handler,false);//注意:這裏默認使用了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);//注意:這裏默認使用了false(冒泡) }else if(element.detachEvent){ element.detachEvent("on"+type,handler); }else{ element["on"+type]=null; } } }; function handler(){ alert("clicked"); } var button=document.getElementById("button"); EventUtil.addHandler(button,"click",handler); </script> </body> </html>
最後瀏覽器成功彈出「clicked」。