addEventListener 用法

来源:http://www.cnblogs.com/Andyudd/archive/2016/06/14/5583563.html
-Advertisement-
Play Games

addEventListener 用於註冊事件處理程式,IE 中為 attachEvent,我們為什麼講 addEventListener 而不講 attachEvent 呢?一來 attachEvent 比較簡單,二來 addEventListener 才是 DOM 中的標準內容。 簡介 addE ...


addEventListener 用於註冊事件處理程式,IE 中為 attachEvent,我們為什麼講 addEventListener 而不講 attachEvent 呢?一來 attachEvent 比較簡單,二來 addEventListener 才是 DOM 中的標準內容。

簡介

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。

示例

function Go()
{
    //...
}

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

或者 listener 直接就是函數

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

 

 

 

 addEventListener-事件流

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

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

捕獲階段 從根節點開始順序而下,檢測每個節點是否註冊了事件處理程式。如果註冊了事件處理程式,並且 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 無法刪除匿名函數的事件處理程式,只有在物件(比如按鈕)去除之後,該記憶體才可能得到回收。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • scala的訪問修飾符有如下幾個特性: 如果不指定訪問修飾符,scala預設為public; 較之Java,scala對protected的定義更加嚴格; scala可以對可見性進行細粒度的控制。 scala的預設訪問修飾符 如果沒有修飾符,scala會預設把類、欄位、方法的訪問修飾符當做publi... ...
  • 獲取Frame對象 獲取TextField對象 獲取TextArea對象 獲取Button對象 調用Frame對象的add()方法,添加進去 調用TextField對象的getText()方法,可以獲取文本框內的數據 調用TextArea對象的setText()方法,設置文本數據 列目錄 獲取到文本 ...
  • 在上篇的時候,我們知道了:屬性就是屬於一個對象的數據或者函數,我們可以通過句點(.)來訪問屬性,同時 python 還支持在運作中添加和修改屬性。 而數據變數,類似於: name = 'scolia' 這樣的形式,會稱其為欄位;而類裡面的函數,又稱為方法。而方法又分為實例方法,類方法和靜態方法,這些 ...
  • 本文內容主要總結自《Java併發編程的藝術》第5章——Java中的鎖。 一、AQS AbstractQueuedSynchronizer(簡稱AQS),隊列同步器,是用來構建鎖或者其他同步組建的基礎框架。該類主要包括: 1、模式,分為共用和獨占。 2、volatile int state,用來表示鎖 ...
  • 異常的練習: 老師用電腦上課。開始思考上課中出現的問題。比如問題是 電腦藍屏。 電腦冒煙。要對問題進行描述,封裝成對象。可是當冒煙發生後,出現講課進度無法繼續。出現了講師的問題:課時計劃無法完成。 運行結果: NoPlanException: 上課無法繼續,因為電腦冒煙了 class Teacher ...
  • C++的深拷貝和淺拷貝 淺拷貝也叫位拷貝(bitwise assignment),意思就是將一個對象的記憶體映像按位原封不動的複製給另一個對象。如果欄位是值類型的,則對該欄位執行逐位複製;如果欄位是引用類型,則複製引用但不複製引用的對象。 如果改變目標對象中引用型欄位的值他將反映在原是對象中,也就是說 ...
  • http://blog.csdn.net/csh624366188/article/details/7183872 http://www.cnblogs.com/zhhh/archive/2011/06/10/2077519.html 又看到有人在問三層架構和MVC的關係,感覺這種問題有點教條化了。 ...
  • 1.點擊桌面的我Windows 圖標,找打控制面板 2.進入控制面板主頁,選擇系統和安全,進入系統和安全 3.進入系統和安全主頁後選擇管理工具,點擊進入 4.進入管理工具後,選擇數據源,進行數據源的配置 5.打開頁面之後點擊添加 6.打開添加頁面,選擇SQL SEVER 然後選擇完成 7.完成後進入 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...