Skip to content

addEventListener 實作:從綁定事件到修改 DOM 屬性

就來寫個事件處理:addEventListener 實作

知道了 事件的種類事件級別 之後,這篇就來把它們串起來:選取 DOM → 掛上監聽器 → 改變畫面

建立 id 屬性

<img> 的屬性中建立一個 idPic 的屬性,讓 JavaScript 來選取。

html
<body>
  <img src="./images/logo.jpg" id="Pic" width="300" height="400" alt="Logo">
</body>

小提醒

Pic 為自行定義的名稱,Away 習慣為 id 設置的值以大駝峰命名。

為不同的事件類型建立監聽器

  1. 從文件中,選取欲綁定事件的 DOM 物件。
    js
    document.querySelector('#Pic')
  2. 建立事件監聽器。
    js
    document.querySelector('#Pic').addEventListener();
  3. 加入 事件類型執行事項 兩個參數。
    js
    document.querySelector('#Pic').addEventListener('click', () => {});

以下為授課的教學案例:

js
document.querySelector('#Pic').addEventListener('click', () => {
  console.log('click');
});

document.querySelector('#Pic').addEventListener('mouseenter', () => {
  console.log('mouseenter');
});

document.querySelector('#Pic').addEventListener('mouseleave', () => {
  console.log('mouseleave');
});

小提醒

同一個元素綁三個不同事件完全沒問題,這正是 addEventListener() 相對於 onclick 的優勢。若上面的 console.log() 沒有反應,請先確認 選取 有沒有成功。

設定 DOM 的屬性、值

  1. 從文件中,選取欲設定屬性的 DOM 物件。
    js
    document.querySelector('#Pic');
  2. 設定影像 src 的屬性,影像的路徑以字串來表示。
    js
    document.querySelector('#Pic').src = '';
  3. 寫入影像的路徑。
    js
    document.querySelector('#Pic').src = './images/b5.jpg';

把它與事件合起來,就是最經典的 滑過換圖

js
const elemPic = document.querySelector('#Pic');

elemPic.addEventListener('mouseenter', () => {
  elemPic.src = './images/b5.jpg';
});

elemPic.addEventListener('mouseleave', () => {
  elemPic.src = './images/logo.jpg';
});

想改的是文字或 HTML 內容,請看 節點的屬性

利用索引值來選取對象

html
<figure class="wrap-head" id="Thumb">
  <img class="img-resp img-rounded hover-weak" src="./images/s1.jpg" width="100" height="65">
  <img class="img-resp img-rounded hover-weak" src="./images/s2.jpg" width="100" height="65">
  <img class="img-resp img-rounded hover-weak" src="./images/s3.jpg" width="100" height="65">
  <img class="img-resp img-rounded hover-weak" src="./images/s4.jpg" width="100" height="65">
  <img class="img-resp img-rounded hover-weak" src="./images/s5.jpg" width="100" height="65">
</figure>

querySelectorAll()

可選取出相同的 DOM 並以 NodeList 類陣列的方式回傳。

js
console.log(document.querySelectorAll('#Thumb .img-resp'));

之後便可以用索引方式選取 DOM,索引值由 0 開始。

js
// 選取此選取器的第一個
console.log(document.querySelectorAll('#Thumb .img-resp')[0]);

// 選取此選取器的第二個
console.log(document.querySelectorAll('#Thumb .img-resp')[1]);

children

可選取出指定 DOM 的子層元素並以 HTMLCollection 類陣列的方式回傳。

js
console.log(document.querySelector('#Thumb').children);

之後便可以用索引方式選取 DOM,索引值由 0 開始。

js
// 選取指定 DOM 的子層元素並取出第一個
console.log(document.querySelector('#Thumb').children[0]);

// 選取指定 DOM 的子層元素並取出第二個
console.log(document.querySelector('#Thumb').children[1]);

一次為多個元素綁定事件

有了類陣列,就能用 forEach() 一次綁完:

js
document.querySelectorAll('#Thumb .img-resp').forEach((elemThumb) => {
  elemThumb.addEventListener('click', (e) => {
    console.log(e.target.src);
  });
});

小提醒

元素數量很多,或子元素之後還會動態新增時,改把監聽器綁在父層會更省效能,這個做法叫做 事件委派

常見問題

addEventListener 的兩個必填參數是什麼?

第一個是事件類型的字串,例如:click;第二個是事件觸發時要執行的 函式。兩個都給了,監聽器才會運作。

為什麼綁定事件後點了沒反應?

最常見的原因是選取不到元素,程式比 DOM 早執行時 querySelector() 會回傳 null。先印出選取結果確認,再檢查選取器的大小寫與拼字,也可回頭看 JavaScript 寫在哪裡defer 說明。

querySelectorAll 與 children 有什麼不同?

querySelectorAll() 依選取器搜尋所有符合的元素,範圍不限直接子層;children 只回傳指定元素的直接子元素。前者回傳 NodeList,後者回傳 HTMLCollection

索引值為什麼從 0 開始?

這是多數程式語言的慣例,第一個元素的索引是 0。因此第三張圖片要寫 [2],最後一個則常用 length 減 1 取得。

要為每個元素都綁一次事件嗎?

元素很多時不必。把監聽器綁在共同的父層,再用 事件物件 判斷實際點到誰,也就是 事件委派,數量多或元素會動態新增時更省效能。

延伸閱讀