Js事件詳解(1)事件型別及幾種新增事件處理程式的方法
js中的事件
早期的事件流的兩種解決方案:
1.IE:事件冒泡流
即事件開始時由最具體的元素(DOM中層次最深的那個節點)接收,然後逐級向上傳播到較為不具體的節點(文件)–自下向上。
所有現代的瀏覽器都支援事件冒泡。
2.Netscape Communicator:事件捕獲流。
與IE團隊提出的事件冒泡流剛好相反。由不太具體的節點到具體的節點傳播。
這麼做的目的:在事件到達預定的目標之前捕獲它。
目前主流的瀏覽器都支援事件流模型,但是老的瀏覽器可能不支援。
所以,請大膽放心使用事件冒泡模型吧。
一、DOM事件流
“DOM2級事件”規定事件流的三個階段:
1.事件捕獲階段
2.處理目標階段
3.事件冒泡階段
【圖13-3】
三個階段按順序執行,一般在事件的冒泡的階段對事件作出響應。
注意:
1.儘管”DOM2級事件”規範明確要求捕獲階段不會涉及事件目標,但是主流瀏覽器都會在事件捕獲階段觸發事件物件上的事件。結果,就是有2個機會在目標物件上面操作事件。
2.IE8之前不支援DOM事件流。
二、事件處理程式
說白了,就是響應事件的函式。一般以’on’開頭,如onload、onclick等。
新增事件處理程式的集中的幾種方法:
1.HTML事件處理程式
某個dom元素支援的每種事件,都可以使用一個與相應事件處理程式同名的HTML特性來指定。
如:
<input type ="button" value="Click Me" onclick="alert('Clicked')" />
或者:
<script type="text/javascript">
function showMessage(){
alert("Hello world!");
}
</script>
<input type="button" value="Click Me" onclick="showMessage()" />
這樣指定事件處理程式,會建立一個封裝著元素屬性值的函式(函式中的this就代表中當前的dom元素),這個函式中有一個區域性變數event,也就是事件物件。
<input type="button" value="Click Me" onclick="alert(event.type)">
<input type="button" value="Click Me" onclick="alert(this.value)">
關於這個動態建立的函式,更有意思的是它的擴充套件作用域的方式,它是這麼幹的:
function(){
with(document){
with(this){
//元素的屬性值
}
}
}
這麼幹的話,讓訪問元素自己的屬性就變得簡單多了。
<input type="button" value="Click Me" onclick="alert(value)">
當該元素是表單元素的話,則作用域還會包含訪問表單元素(當前元素的父元素)的入口:
function(){
with(document){
with(this.form){
with(this){
//元素屬性
}
}
}
}
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="Echo Username" onclick="alert(username.value)">
</form>
這樣擴充套件作用域的方式,無非就是想讓事件處理程式無需引用表單元素就能訪問其他表單欄位。
這種新增事件處理方式的缺點:
<1>.存在時差:
如果事件處理函式寫在元素的下面,可能元素先被解析出來,而事件處理程式對應的函式還沒有被加載出來,此時,若是響應事件會出錯的。
<2>.這種擴充套件事件處理程式的作用域的方式在不同的瀏覽器中實現是不一樣的。
<3>.HTML程式碼與Js程式碼緊密耦合。
2.DOM0級事件處理程式
每個元素(包括window和document)都有自己的事件處理程式屬性,這些屬性通常全部小寫,例如:onclick。
var btn = document.getElementById('myBtn');
btn.onclick = function(){
alert(this.id);
}
使用DOM0級事件指定的事件處理程式被認為是元素的方法,所以事件處理程式中的this指的是當前元素,可以通過this訪問該元素的其他屬性。即事件在當前元素的作用域中執行。
刪除事件處理程式:
btn.onclick = null;
3.DOM2級事件處理程式
addEventListener()
removeEventListener()
該兩個函式接受三個引數:事件名、事件處理函式、布林值(true表示事件在捕獲階段呼叫事件處理程式,false,表示在冒泡階段呼叫事件處理程式)
var btn = document.getElementById('myBtn');
btn.addEventListener('click',function(){
alert(this.id);//this仍表示當前觸發事件的元素
},false);
可以為一個元素新增多個事件處理程式,事件按照新增事件處理程式的順序響應。
removeEventListener():移除事件,第二個引數必須和addEventListener()的第二個引數,這意味著事件處理函式不能是匿名函式,否則不能移除。
關於第三個引數,強烈建議設定為false,即在冒泡階段處理事件,為了最大限度相容各大瀏覽器。
4.IE事件處理程式
提供了兩個方法新增和移除事件處理程式:
attachEvent()
detachEvent()
第一個引數是事件處理程式名(”on”+事件名),第二個引數是事件處理程式。
var btn = document.getElementById('myBtn');
btn.attachEvent('onclick',function(){
alert('click');
});
注意:
和DOM0級事件和DOM2級事件所不同的是,IE事件的處理程式不是執行在元素的作用域中,而是執行在全域性作用域中。即IE指定的事件處理程式中this表示的window物件。
可以為一個元素新增多個事件處理程式,但是執行的順序是倒著執行的,即最後新增的事件處理程式最先執行。
移除事件處理程式:
detachEvent()
匿名的事件處理程式不能移除。
5.跨瀏覽器的事件處理程式
其實就是檢測各個瀏覽器支援的事件型別。預設採用DOM0級方法。
var EventUtil = {
addHandler:function(element, type, handler){
if(element.addEventListener){//判斷是否支援DOM2級事件處理
element.addEventListener(type,handler,false);
}else if(element.attachEvent){
element.attachEvent('on'+type,handler);
}else{
element['on'+type] = handler;//預設採用DOM0級方法。
}
},
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;
}
}
};
注意:
<1>這裡只是簡單考慮了對元素的新增和移除事件處理程式,並沒有考慮其他的問題,如,事件處理程式執行作用域的問題。
<2>DOM級事件只支援新增一個事件處理程式,即你多次呼叫這個方法為元素新增多個事件處理程式,結果,只會新增最後一個。不過,現在只支援DOM0的瀏覽器好像也不多了,所以一般不會走到最後一個else。