前面的話
事件處理程序又叫事件偵聽器,實際上就是事件的綁定函數。事件發生時會執行函數中相應代碼。事件處理程序有HTML事件處理程序、DOM0級事件處理程序、DOM2級事件處理程序和IE事件處理程序四類,下面將詳細介紹該部分內容
HTML事件處理程序
某個元素支持的每種事件,都可以使用一個與相應事件處理程序同名的HTML特性來指定。這個特性的值應該是能夠執行的javascript代碼
在事件處理程序函數內部,this值等于事件的目標元素
<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= '1';"></div>
在HTML中定義的事件處理程序也可以調用在頁面其他地方定義的腳本
<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "test()"></div> <script> function test(){box.innerHTML+= '1';} </script>
HTML事件處理程序會創建一個封裝著元素屬性值的函數。這個函數中有一個局部變量event,也就是事件對象。通過event變量,可以直接訪問事件對象,不用自己定義它,也不用從函數的參數列表中獲取
<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= event.type;"></div>
在事件處理程序函數內部,可以像訪問局部變量一樣訪問document及該元素本身的成員。如此一來,事件處理程序要訪問自己的屬性就簡單多了
<button id="box" value="test" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= value;"></button>
【擴展】
下列這種情況輸出的是空字符串'',如果與預想結果不一致,請移步至此
<script> var value=123; </script> <button style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= value;"></button>
缺點
【1】時差問題
因為用戶可能會有HTML元素一出現在頁面上時就觸發相應的事件,但當時的事件處理程序有可能尚不具備執行條件,就會報錯
<button style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= val;"></button> <script src="http://www.qq.com/test.js"></script> <script> var val=123; </script>
【2】耦合問題
客戶端編程的通用風格是保持HTML內容和javaScript行為分離,所以應該避免使用HTML事件處理程序屬性,因為這些屬性直接混合了javascript和HTML,且不易擴展
DOM0級事件處理程序
通過javascript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。這種為事件處理程序賦值的方法是在第四代Web瀏覽器中出現的,而且至今仍然為所有現代瀏覽器所支持。原因一是簡單,二是具有跨瀏覽器的優勢
每個元素都有自己的事件處理程序屬性,這些屬性通常全部小寫,將這種屬性的值設置為一個函數,就可以指定事件處理程序
[注意]以DOM0級方式添加的事件處理程序會在事件流的冒泡階段被處理
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.onclick = function(){this.innerHTML += '1';} </script>
可以通過將事件處理程序屬性設置為null來刪除事件處理程序
box.onclick = null;
缺點
DOM0級事件處理程序的缺點是圍繞著每個事件目標對于每種事件類型只能添加一個事件處理程序
DOM2級事件處理程序
DOM2級事件處理程序定義了兩個方法用于處理指定和刪除事件處理程序的操作:addEventListener()和removeEventListener()
所有DOM節點中都包含這兩個方法,并且它們都接受3個參數:要處理的事件名、作為事件處理程序的函數和一個布爾值。最后的布爾值參數如果是true,表示在捕獲階段調用事件處理程序;如果是false,表示在冒泡階段調用事件處理程序。若最后的布爾值不填寫,則和false效果一樣
[注意]IE8-瀏覽器不支持DOM2級事件處理程序
使用DOM2級事件處理程序的好處是可以添加多個事件處理程序,并按照他們添加的順序觸發
以下代碼以1-2的順序輸出
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.addEventListener('click',function(){this.innerHTML += '1'},false); box.addEventListener('click',function(){this.innerHTML += '2'},false); </script>
以下代碼以2-1的順序輸出
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> setTimeout(function(){ box.addEventListener('click',function(){this.innerHTML += '1'},false); },16); box.addEventListener('click',function(){this.innerHTML += '2'},false); </script>
參數
如果希望向監聽函數傳遞參數,可以用匿名函數包裝一下監聽函數
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.addEventListener("click",function(){ test('123'); },false); function test(x){box.innerHTML += x;} </script>
移除
通過addEventListener()添加的事件處理程序只能使用removeEventListener()來移除,移除時傳入的參數與添加處理程序時使用的參數相同。這意味著,addEventListener()添加的匿名函數將無法移除
以下無效
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.addEventListener("click",function(){ this.innerHTML += '1' },false); box.removeEventListener('click',function(){ this.innerHTML += '1' },false); </script>
以下有效
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> var handle = function(){this.innerHTML += '1'}; box.addEventListener("click",handle,false); box.removeEventListener('click',handle,false); </script>
IE事件處理程序
IE實現了與DOM中類似的兩個方法:attachEvent()和detachEvent()。這兩個方法接受相同的兩個參數:事件處理程序名稱與事件處理程序函數。由于IE8-瀏覽器只支持事件冒泡,所以通過attachEvent()添加的事件處理程序都會被添加到事件冒泡階段
attachEvent()方法的第一個參數是"onclick",而非DOM的addEventListener()方法中的"click"
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.attachEvent('onclick',function(){this.innerHTML += '1';}); </script>
[注意]attachEvent()方法只冒泡到document,且IE10-瀏覽器支持
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <button id="reset">還原</button> <script> //IE10-瀏覽器返回div body html document //其他瀏覽器報錯 reset.onclick = function(){history.go();} box.attachEvent('onclick',function(){box.innerHTML += 'div\n';}); document.body.attachEvent('onclick',function(){box.innerHTML += 'body\n';}); document.documentElement.attachEvent('onclick',function(){box.innerHTML += 'html\n';}); document.attachEvent('onclick',function(){box.innerHTML += 'document\n';}); window.attachEvent('onclick',function(){box.innerHTML += 'window\n';}); </script>
this
與其他三個事件處理程序不同,IE事件處理程序的this指向window,而非被綁定事件的元素
<!-- <div> --> <div id="box" style="height:100px;width:300px;background-color:pink;" onclick = "console.log(this)"></div>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div> <script> box.onclick= function(){ console.log(this);//<div> } </script>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div> <script> box.addEventListener('click',function(){ console.log(this);//<div> }); </script>
<div id="box" style="height:100px;width:300px;background-color:pink;"></div> <script> box.attachEvent('onclick',function(){ console.log(this);//window }); </script>
順序
使用attachEvent()方法添加的事件處理程序的觸發順序是有區別的。IE9、10瀏覽器是按正序執行的,而IE8-瀏覽器則是按倒序執行的
<div id="box" style="height:30px;width:100px;background-color:pink;"></div> <script> box.attachEvent('onclick',function(){ box.innerHTML += '1'; }); box.attachEvent('onclick',function(){ box.innerHTML += '2'; }); </script>
移除
使用attachEvent()添加的事件可以通過detachEvent()來移除,條件是必須提供相同的參數。與DOM方法一樣,這也意味著添加的匿名函數將不能被移除。不過,只要能夠將對相同函數的引用傳給detachEvent(),就可以移除相應的事件處理程序
以下無效
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> box.attachEvent("onclick",function(){ box.innerHTML += '1' },false); box.detachEvent('onclick',function(){ box.innerHTML += '1' },false); </script>
以下有效
<div id="box" style="height:30px;width:200px;background-color:pink;"></div> <script> var handle = function(){box.innerHTML += '1'}; box.attachEvent("onclick",handle,false); box.detachEvent('onclick',handle,false); </script>
總結
由于IE8-瀏覽器不支持addEventListener()方法,所以需要配合attachEvent()方法來實現全瀏覽器的事件綁定兼容寫法。同時,由于attachEvent()方法中的this指向window,所以需要對this進行顯式修改
function addEvent(target,type,handler){
if(target.addEventListener){
target.addEventListener(type,handler,false);
}else{
target.attachEvent('on'+type,function(event){
return handler.call(target,event);
});
}
}
調用順序
如果瀏覽器同時出現這四種事件處理程序,那么它們的調用順序在各瀏覽器中表現并不一致
<div id="box" style="height:100px;width:100px;background:pink;" onclick = "this.innerHTML +='html\n'"></div> <script> if(box.addEventListener){ box.addEventListener('click',function(){this.innerHTML += 'DOM2級\n'}) } if(box.attachEvent){ box.attachEvent('onclick',function(){box.innerHTML +='IE\n'}) } box.onclick = function(){ this.innerHTML += 'DOM0級\n'; } </script>
【相同點】
如果同時出現HTML事件處理程序和DOM0級事件處理程序,DOM0級會覆蓋HTML事件處理程序
【不同點】
chrome/opera/safari等webkit內核的瀏覽器會按照事件處理程序出現的順序來排列,所以結果為:DOM2級 DOM0級
firefox瀏覽器和IE瀏覽器會將DOM0級事件優先調用
所以firefox和IE11瀏覽器結果為:DOM0級 DOM2級
IE9、10瀏覽器結果為:DOM0級 DOM2級 IE
IE8-瀏覽器結果為:DOM0級 IE
文章列表