Day25:派一個Spy到網頁中竊聽—事件監聽


先來說說什麼是「事件」吧?

舉個例子:看到紅燈,就踩剎車!

「看到紅燈」就是事件;「踩剎車」就是事件發生後所採取的行動。而在網頁上所發生的事件,可能是使用者滑鼠點擊、滑鼠移入、滾動瀏覽器卷軸、改變視窗大小…等等。

瀏覽器載入網頁時,會把所有的 JavaScript 程式碼載入,但是並不是所有程式碼都會馬上執行,有些必須等到「事件發生」,才會執行相對應的程式碼,例如,「按下按鈕」,跳出「對話框」。「按下按鈕」是事件( Event ),「跳出對話框」就是執行相對應的程式碼( Event Handler )。

當然你必須要把監聽的事件( Event )跟你要執行的程式碼( Event Handler )綁定在一起,事件發生時兩者才會連動。

目前綁定的方法有:

  • 由網頁上HTML元素上綁定 on-event 處理器
  • 利用 DOM API 所提供的 on-event 處理器來綁定

在網頁上HTML元素上綁定 on-event 處理器

在HTML元素上透過「on + 事件名稱」來綁定事件,只要事件被觸發,就會執行 JavaScript。

<button id="btn" onclick="alert('降龍十八掌之亢龍有悔')">點擊出招</button>

在早期都是透過這種方式綁定事件,但隨著觀念的進化,這種「侵入式的寫法」容易造成資安漏洞,也不符合「關注點分離」,由HTML 負責架構與內容, JavaScript 負責互動的觀念。現在比較少用這種綁定事件的方式了。

利用DOM API所提供的on-event處理器來綁定

也可以在 JavaScript 中藉由 document.getElementById() 或 document.querySelector() 選取 HTML 元素當節點,然後將 on-event 綁定在選取的節點上。

<button id="btn">點擊出招</button>
//選取節點
let btn = document.getElementById('btn');
//將on-event綁定在事件上
btn.onclick = function(){
	alert('降龍十八掌之見龍在田');
};

如果希望 HTML 一載入瀏覽器, JavaScript 就自動執行,可以這樣寫:

window.onload = function(){
	alert('飛雪連天射白鹿,笑書神俠倚碧鴛');
}

事件監聽

為了要偵測使用者對網頁所做的行為,如果可以在網頁中埋伏一個間諜,監看使用者是否有對指定的元素做出設定好的動作,如果有的話,就給予相對的回應,這樣就會方便得多。

那該如何來做事件監聽呢?基本上「事件監聽」長成這個樣子:

HTML元素節點.addEventListener('事件名稱',事件處理器,boolean值)

「事件名稱」指的是使用者對綁定的 HTML 元素節點所做的事情,例如點擊( click )、滑鼠移入( mouseenter )…等事件。

「事件處理器」( Event Handler )指的是事件發生時,要叫用的 function()。

布林值( boolean ), false 代表事件冒泡( Event Bubbling ),而 true 代表事件捕捉( Event Capturing )。這是甚麼意思呢?

事件冒泡( Event Bubbling ):由啟動事件的元素節點開始,向外層傳遞。

事件捕捉( Event Capturing ):由最外層開始,一層一層找到啟動事件的元素節點。

<!DOCTYPE html>
<html>
<head>
	<title>標題</title>
</head>
<body>
	<div>點我--隔山打牛--點我</div>
</body>

事件觸發的傳遞順序會是:

  1. <div>點我–隔山打牛–點我</div>
  2. <body>
  3. <html>
  4. document

因為<div>點我–隔山打牛–點我</div>也是在<body>的範圍中,所以點擊它的同時也會傳遞到<body>,跟著也會傳到<html>與document。這種click事件一層一層往上依序被觸發,就是「事件冒泡」機制。

而「事件捕獲」傳遞的順序則相反,同樣是點擊<div>點我–隔山打牛–點我</div>,但是傳遞順序卻如下:

  1. document
  2. <html>
  3. <body>
  4. <div>點我–隔山打牛–點我</div>

講解完事件綁定,來看一下事件綁定的簡單例子:

<button id="btn">用滑鼠點穴</button>
let btn = document.getElementById('btn');
btn.addEventListener('click',function(){
	alert('腳麻袂凍行');
},false)

**而且同元素的同一事件可以重複指定addEventListener()**:

let btn = document.getElementById('btn');
btn.addEventListener('click',function(){
	alert('腳麻袂凍行');
},false)

btn.addEventListener('click',function(){
	alert('快吃循力寧');
},false)

如果是 on-event 的方法如果重複綁定的話,則只會出現最後一個綁定的事件。

<input type="button" onclick = "alert('見龍在田')" value="行內綁定">
<!-- 使用on-event綁定 -->
<input type="button" class="btnOn" value="on-event點擊">
<!-- 使用addEventListener綁定 -->
<input type="button" class="btnAdd" value="addEvent點擊">
var elOn = document.querySelector('.btnOn');

elOn.onclick = function(){
  alert('on-1');
}
//雖然同一物件綁訂了兩個on事件處理器,但是只會出現最後一個on-2
elOn.onclick = function(){
  alert('on-2');
}

var elAdd = document.querySelector('.btnAdd');

elAdd.addEventListener('click',function(){
  alert('add點擊1');
},false)
//同一物件綁訂了兩個addEventListener,兩個綁定的事件處理器都會執行
elAdd.addEventListener('click',function(){
  alert('add點擊2');
},false) 

那如果要解除 addEventListener() 綁定的事件,可以使用 removeEventListener() 。

HTML元素節點.addEventListener('事件名稱',事件處理器,boolean值)

but,要注意的是「事件處理器」必須要指向同一個「實體」,在下面範例中指的是相同名稱的 function。

let btn = document.getElementById('btn');
btn.addEventListener('click',function(){
	alert('腳麻袂凍行');
},false)
//愛到不能動,還有甚麼值得我心痛,沒辦法移除事件,因為指向不同實體
btn.removeEventListener('click',function(){
	alert('腳麻袂凍行');
},false)

要這麼做才行:

```jsx
let btn = document.getElementById(‘btn’);

let canNotMove = function() {
alert(‘腳麻袂凍行’);
}

btn.addEventListener(‘click’, canNotMove, false);

btn.removeEventListener(‘click’, canNotMove, false);


Day25:派一個Spy到網頁中竊聽—事件監聽
https://popeye-ux.github.io/2021/09/25/21-day25-addEventListener/
作者
POPEYE
發布於
2021年9月25日
許可協議