深刻理解DOM事件機制系列第二篇——事件處理程序

前面的話

  事件處理程序又叫事件偵聽器,實際上就是事件的綁定函數。事件發生時會執行函數中相應代碼。事件處理程序有HTML事件處理程序、DOM0級事件處理程序、DOM2級事件處理程序和IE事件處理程序四類,下面將詳細介紹該部份內容javascript

 

HTML事件處理程序

  某個元素支持的每種事件,均可以使用一個與相應事件處理程序同名的HTML特性來指定。這個特性的值應該是可以執行的javascript代碼html

  在事件處理程序函數內部,this值等於事件的目標元素java

<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "this.innerHTML+= '1';"></div>

  在HTML中定義的事件處理程序也能夠調用在頁面其餘地方定義的腳本web

<div id="box" style="height:30px;width:200px;background-color:pink;"onclick = "test()"></div>
<script>
    function test(){box.innerHTML+= '1';}    
</script>

  HTML事件處理程序會建立一個封裝着元素屬性值的函數。這個函數中有一個局部變量event,也就是事件對象。經過event變量,能夠直接訪問事件對象,不用本身定義它,也不用從函數的參數列表中獲取chrome

<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>

缺點this

【1】時差問題spa

  由於用戶可能會有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()方法添加的事件處理程序的觸發順序是有區別的。IE九、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級

  IE九、10瀏覽器結果爲:DOM0級 DOM2級 IE

  IE8-瀏覽器結果爲:DOM0級 IE

相關文章
相關標籤/搜索