addEventListener

addEventListener

addEventListener-開始javascript

 

前面零散地寫了些關於 addEventListener 的內容,以爲比較散,有些地方可能也說得不夠清楚明白,因此決定以連載的形式從頭至尾再寫一篇。css

addEventListener 用於註冊事件處理程序,IE 中爲 attachEvent,咱們爲何講 addEventListener 而不講 attachEvent 呢?一來 attachEvent 比較簡單,二來 addEventListener 纔是 DOM 中的標準內容。html

簡介java

addEventListener 爲文檔節點、document、window 或 XMLHttpRequest 註冊事件處理程序,在之前咱們通常是 <input type="button" onclick="...",或 document.getElementById("testButton").onclick = FuncName, 而在 DOM 中,咱們用 addEventListener(IE 中用 attachEvent)。瀏覽器

語法函數

target.addEventListener(type, listener, useCapture);
  • target 文檔節點、document、window 或 XMLHttpRequest。
  • type 字符串,事件名稱,不含「on」,好比「click」、「mouseover」、「keydown」等。
  • listener 實現了 EventListener 接口或者是 JavaScript 中的函數。
  • useCapture 是否使用捕捉,看了後面的事件流一節後就明白了,通常用 false。

示例post

function Go()
{
    //...
}

document.getElementById("testButton").addEventListener("click", Go, false);

或者 listener 直接就是函數測試

document.getElementById("testButton").addEventListener("click", function () { ... }, false);

 

 

 

 addEventListener-事件流ui

說到 addEventListener 不得不說到事件流,先說事件流對後面的解釋比較方便。this

當一個事件發生時,分爲三個階段:

捕獲階段 從根節點開始順序而下,檢測每一個節點是否註冊了事件處理程序。若是註冊了事件處理程序,而且 useCapture 爲 true,則調用該事件處理程序。(IE 中無此階段。)

目標階段 觸發在目標對象自己註冊的事件處理程序,也稱正常事件派發階段。

冒泡階段 從目標節點到根節點,檢測每一個節點是否註冊了事件處理程序,若是註冊了事件處理程序,而且 useCapture 爲 false,則調用該事件處理程序。

舉例

<div id="div1">
  <div id="div2">
    <div id="div3">
      <div id="div4">
      </div>
    </div>
  </div>
</div>

若是在 d3 上點擊鼠標,事件流是這樣的:

捕獲階段 在 div1 處檢測是否有 useCapture 爲 true 的事件處理程序,如有,則執行該程序,而後再一樣地處理 div2。

目標階段 在 div3 處,發現 div3 就是鼠標點擊的節點,因此這裏爲目標階段,如有事件處理程序,則執行該程序,這裏不論 useCapture 爲 true 仍是 false。

冒泡階段 在 div2 處檢測是否有 useCapture 爲 false 的事件處理程序,如有,則執行該程序,而後再一樣地處理 div1。

注意,上述捕獲階段和冒泡階段中,實際上 div1 之上還應該有結點,好比有 body,但這裏不討論。

 

 

 

 

 

addEventListener-第三個參數 useCapture

 

addEventListener 有三個參數:第一個參數表示事件名稱(不含 on,如 "click");第二個參數表示要接收事件處理的函數;第三個參數爲 useCapture,本文就講解它。

<div id="outDiv">
  <div id="middleDiv">
    <div id="inDiv">請在此點擊鼠標。</div>
  </div>
</div>

<div id="info"></div>

 

var outDiv = document.getElementById("outDiv");
var middleDiv = document.getElementById("middleDiv");
var inDiv = document.getElementById("inDiv");
var info = document.getElementById("info");
 
outDiv.addEventListener("click", function () { info.innerHTML += "outDiv" + "<br>"; }, false);
middleDiv.addEventListener("click", function () { info.innerHTML += "middleDiv" + "<br>"; }, false);
inDiv.addEventListener("click", function () { info.innerHTML += "inDiv" + "<br>"; }, false);

上述是咱們測試的代碼,根據 info 的顯示來肯定觸發的順序,有三個 addEventListener,而 useCapture 可選值爲 true 和 false,因此 2*2*2,能夠得出 8 段不一樣的程序。

  • 全爲 false 時,觸發順序爲:inDiv、middleDiv、outDiv;
  • 全爲 true 時,觸發順序爲:outDiv、middleDiv、inDiv;
  • outDiv 爲 true,其餘爲 false 時,觸發順序爲:outDiv、inDiv、middleDiv;
  • middleDiv 爲 true,其餘爲 false 時,觸發順序爲:middleDiv、inDiv、outDiv;
  • ……

最終得出以下結論:

  • true 的觸發順序老是在 false 以前;
  • 若是多個均爲 true,則外層的觸發先於內層;
  • 若是多個均爲 false,則內層的觸發先於外層。

下面提供所有代碼,您能夠更改其中的 true、false 值,來進行測試。注意,不適用於 IE。

 

 


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Language" content="zh-cn" />
<meta http-equiv="Content-Type" content="text/html; charset=gb2312" />
<title>useCapture</title>
<style type="text/css">
#outDiv
{
    padding:10px 10px 10px 10px;
    border:1px solid red;
}

#middleDiv
{
    padding:10px 10px 10px 10px;
    border:1px solid green;
}

#inDiv
{
    padding:10px 10px 10px 10px;
    border:1px solid blue;
}
</style>
</head>

<body>

<div id="outDiv">
  <div id="middleDiv">
    <div id="inDiv">請在此點擊鼠標。</div>
  </div>
</div>

<div id="info"></div>

<script language="javascript" type="text/javascript">
<!--

var outDiv = document.getElementById("outDiv");
var middleDiv = document.getElementById("middleDiv");
var inDiv = document.getElementById("inDiv");
var info = document.getElementById("info");
 
outDiv.addEventListener("click", function () { info.innerHTML += "outDiv" + "<br>"; }, false);
middleDiv.addEventListener("click", function () { info.innerHTML += "middleDiv" + "<br>"; }, false);
inDiv.addEventListener("click", function () { info.innerHTML += "inDiv" + "<br>"; }, false);
//-->
</script>

</body>

</html>

 

addEventListener-event 對象的屬性和方法

 

事件觸發時,會將一個 Event 對象傳遞給事件處理程序,好比:

document.getElementById("testText").addEventListener("keydown", function (event) { alert(event.keyCode); }, false);

事件類型

DOM 事件類型是分爲 UIEvent、UIEvent:KeyEvent、UIEvent:MouseEvent,不一樣的事件有不一樣的屬性和方法,但經常使用的來講咱們都不會用錯,好比咱們不會在鼠標事件中去取鍵盤值(Ctrl、Alt、Shift 除外),因此咱們沒有必要深究。

該對象的屬性和方法有:

view 只讀,對象,發生事件的 Window 對象。

type 只讀,字符串。好比鼠標點擊事件的類型:click。

eventPhase 只讀,數字,事件流正經歷的階段。1-捕獲,2-目標,3-冒泡。

target 只讀,對象,派發事件的目標對象。好比鼠標是點擊在哪一個按鈕上的。

currentTarget 只讀,對象,當前正在調用監聽器的對象,也就是當前 addEventListener 是綁定在哪一個對象上的。

timeStamp 只讀,數字,用毫秒錶示事件發生時距計算機開機的時間。


 

cancelable 只讀,布爾,處理事件的默認行爲是否能夠中止。主要針對一些系統事件,若是值爲 true,則 event 的 preventDefault 方法可使用,不然不可用。

preventDefault() 阻止瀏覽器的默認行爲,好比在文本框中打字觸發 keydown,若是 keydown 事件處理程序中調用了 preventDefault(),所打的字就不會跑到文本框中去,注意,此時不要彈出 alert 對話框,不然可能不起做用。IE 中在事件處理程序中用 return false 實現相似功能。


 

bubbles 只讀,布爾,事件是否開啓冒泡功能。

stopImmediatePropagation 這個東西在 JavaScript 中是個屬性,而不是方法,布爾,但具體測試並未發現其用途,不知是否是 bug。

stopPropagation() 中止當前的事件流傳播,但不會中止當前正在處理的對象。IE 中用 event.cancelBubble =  true 實現相似功能。

cancelBubble 布爾,是否取消冒泡,不建議使用,用 stopPropagation() 代替。

preventBubble() 阻止冒泡,不建議使用,用 stopPropagation() 代替。

preventCapture() 阻止捕獲,不建議使用,用 stopPropagation() 代替。


 

detail 只讀,數字,提供時間的額外信息,對於 click 事件、mousedown 事件和 mouseup 事件,這個字段表明點擊的次數。

isChar 只讀,布爾,按下的按鍵值是不是字符,好比按下 Ctrl 鍵時,就返回 false。不過您在 Firefox 中測試時,該值老是 false,Firefox 官方已經說明這是一個 bug。

altKey 只讀,布爾,是否按下了 Alt 鍵。

ctrlKey 只讀,布爾,是否按下了 Ctrl 鍵。

shiftKey 只讀,布爾,是否按下了 Shift 鍵。

metaKey 只讀,布爾,是否按下了 Meta 鍵。


 

下面一些屬性頗有意思,請仔細區別。

charCode 只讀,數字,字符(英文、數字、符號)的 Unicode 值。

  • 只用於 keypress。

keyCode 只讀,數字,鍵盤按鍵值。

  • 用於 keypress 時:返回非字符按鍵值(除 Ctrl、Shift、Alt、Caps Lock、單行文本框中按向上鍵等);
  • 用於 keydown、keyup 時:返回任意鍵值。

button 只讀,數字,鼠標按鍵值。

  • 用於 click 時:0-左鍵。
  • 用於 mousedown、mouseup 時:0-左鍵,1-中間鍵(滾輪),2-右鍵。

which 只讀,數字,鍵盤按鍵值或鼠標按鍵值。

  • 用於 keypress 時:等同於 charCode + 回退鍵 + 回車鍵;
  • 用於 keydown、keyup 時:返回任意鍵值;
  • 用於 click 時:1-左鍵,與 button 的值略有區別。
  • 用於 mousedown、mouseup 時:1-左鍵,2-中間鍵(滾輪),3-右鍵,與 button 的值略有區別。

能夠看出,which 只有一點沒有包括:那就是 keypress 時,不如 keyCode 那麼全,但實際上,keypress 事件中用於非字符鍵的狀況較少,因此通常仍是用 which 代替所有。

 

 

addEventListener-有用的筆記

 

爲何用 addEventListener

  • 能夠對同一物件的同一事件綁定多個事件處理程序。
  • 能夠經過事件流三個階段更好地控制什麼時候觸發事件處理程序。
  • 工做於 DOM 元素,而不只是 HTML 元素。

事件分發時添加 eventListener

不會當即觸發 eventListener,可能會在下一個事件流(好比冒泡階段)中觸發。

多個相同的 eventListener

以下,三個參數徹底相同,而且第二個參數不是匿名函數。

document.getElementById("myBox").addEventListener("click", Go, false);
document.getElementById("myBox").addEventListener("click", Go, false);
document.getElementById("myBox").addEventListener("click", Go, false);

會拋棄多餘的,只保留一個,對應的 removeEventListener 也只用一次就能夠了(removeEventListener 用法和 addEventListener 徹底相同)。

但若是是第二個參數是匿名函數,好比:

document.getElementById("outDiv").addEventListener("click", function () { document.getElementById("info").innerHTML += "1";}, false);
document.getElementById("outDiv").addEventListener("click", function () { document.getElementById("info").innerHTML += "1";}, false);
document.getElementById("outDiv").addEventListener("click", function () { document.getElementById("info").innerHTML += "1";}, false);

則三個均有效,而且沒法用 removeEventListener 除去。

this

事件處理程序中,this 變成了觸發事件的控件,但咱們仍推薦用 event.target 或 event.currentTarget。

早期的事件監聽

在 DOM0 中,咱們用 obj.onclick = FuncName,因爲兼容性好,應用很是普遍,只是功能不如 addEventListener 強大。

內存問題

前面提到了許多使用域名函數的地方,有時這是沒辦法的,請參見在各瀏覽器中動態添加事件-參數篇,但這會致使內存問題。

一旦事件綁定以後,該綁定代碼做用域的變量就都保留下來,不會被 JavaScript 引擎回收,這可能會引發佔用大量內存的問題,因爲 removeEventListener 沒法刪除匿名函數的事件處理程序,只有在物件(好比按鈕)去除以後,該內存纔可能獲得回收。

相關文章
相關標籤/搜索