DOM事件流

一直以來,在DOM中添加事件總是使用三種方法,

第一種使用HTML中的事件處理程序例如:

<button onclick=' $$ '></button>

第二種:使用在JavaScript中添加事件處理程序:

var s =document.getElementById('id');
s.oncilck=function(){}

第三種使用 addEventListener 方法註冊事件處理程序:

document.getElementById('id').addEventListener('click',function(){})//注意是click

一直是這樣用的,卻沒有理解使用的弊端和注意的問題,現在總結一下這三者DOM事件處理方法的優劣。

一、事件流

事件流有兩種,事件冒泡事件捕獲,它表示當用戶觸發了某個頁面元素的動作,應該由怎樣的方式向“觀察者”傳遞;就像是身爲校長的你,學生髮生了一起鬥毆事件,你是通過挨個年級-班級去找到滋事者(事件捕獲);還是通過一個學生主動告訴你事情發生的經過(事件冒泡);某種程度上,中國寫信的地址方式和美國的寫信的地址,有些類似冒泡和捕獲的過程。

1、事件冒泡

假如一篇文檔的結構:

<html>
<head> </head>
<body>
<div></div>
</body>
</html>

當點擊div元素 ,觸發了click事件,那麼冒泡傳遞的方式是這樣的,

2、事件捕獲

自然是反方向的:

3、DOM事件流

很多面試會有問到這個問題,實際上DOM事件流是DOM2級事件中規定的,它包括,事件捕獲階段,目標發生階段,和事件冒泡階段。

 

值得注意的是,div元素不會在捕獲階段接受事件,也就是捕獲的過程到body後就停止了,接下來是目標階段;在事件處理中屬於冒泡階段的一部分,

 DOM2中規定捕獲階段不會設計目標事件,但是高版本瀏覽器沒有遵循規定;因此就有兩個機會在目標對象中操作事件。

 二、事件處理程序

事件的名稱 click ;load;mouseover;事件處理程序以‘on’開頭;因此click事件的事件處理程序就是onclickload事件的事件處理程序就是onload

1、HTML事件處理程序

 HTML事件處理程序可以直接在事件處理程序中,添加執行的函數,也可以進行調用其他地方定義的腳本;

<button oncilck="alert('hello world!')"></button>//執行代碼直接添加到事件中
<script>
function hello(){
alert('hello,world!')
}
</script>

<button onclick='hello()'></button>//調用其他腳本

HTML事件處理程序優點

  • 會創建一個封裝着元素屬性值的函數,這個函數中有一個局部變量event,也就是事件對象。
<input type='button' value='click me' onclick='alert(this.value)'>//click me this值指向發生事件的目標元素;
<input type='button' value='click' onclick='alert(event.type)'>//click 通過event對象可以訪問事件對象;

HTML事件處理程序缺點

  • 失去響應。如果定義的腳本在觸發事件元素的後面進行定義的,很可能在沒有加載腳本之前;用戶點擊了元素,會失去響應;(JavaScript引擎是逐行讀取代碼的)
  • HTML與JavaScript高度耦合,缺乏可維護性和增加維護成本。

2、DOM 0 級事件處理程序

JavaScript中常見的處理事件的方式,通過將函數賦值給一個事件處理程序屬性;簡單,而且跨瀏覽器;

var but=document.getElementById('id');
but.onclick=function(){
    alert(this.value)
}

這種方式的事件 處理程序在事件流的冒泡階段被處理。

but.onclick=null;//阻止事件處理的方式,設置null;

3、DOM 2級事件處理程序

通過addEventListener()    removeEventListener(),方法註冊和刪除事件處理程序,接受3個參數,事件名,處理函數,布爾值;

var but=document.getElementById('id');
but.addEventListener('click',function(){
    alert('this.value');
},false);

布爾值true表示在事件流捕獲階段觸發調用,布爾值false 表示在冒泡階段調用事件處理程序。

注意:

  • 第二個參數是事件名,不是事件處理函數名, ‘click’而不是‘onclick’,與前兩個方式不同。
  • 可以添加多個事件處理程序;處理的順序按照註冊的順序執行。
var but=document.getElementById('id');
but.addEventListener(
'click',function(){ alert('this.value'); },false);
but.addEventListener(
'click',function(){ alert('hello world'); },false);
  • 匿名函數無法通過removeEventListener()方法移除事件處理程序,因爲兩次的匿名函數不是同一個函數,
var but=document.getElementById('id');

but.addEventListener('click',function(){
    alert('hello world');
},false);

but.removeEventListener('click',function(){
    alert('hello world');
},false);//無效,因爲第二個參數是完全不同的匿名函數,只是定義相同;
var but=document.getElementById('id');

function hello(){
    alert('hello world')
}

but.addEventListener('click',hello,false);
but.removeEventListener('click',hello,false)//有效,使用相同函數

4、IE事件處理程序

IE使用attachEvent()  detachEvent()兩個方法添加事件處理,這兩個方法分別接受兩個參數,事件處理名稱,事件處理函數;由於IE8更早版本只支持事件冒泡,因此通過attachEvent() 添加的時間處理程序會被添加到冒泡階段。
注意

  • attachEvent() 第一個參數是“onclick” 而不是“click”;
  • attachEvent() 也可以添加多個事件,不過執行的順序完全相反;
  • 可以通過 detachEvent() 方法移除事件,和removeEventListener() 類似;不能移除匿名函數。
var but=document.getElementById('id');
function hello(){
    alert('hello world')
}

but.attachEvent('onclick',hello);
but.attachEvent('onclick',function(){
    alert('this.id')
})
//先 彈出id ,後彈出 hello world

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章