iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 9
0

前言

昨天我們說到,如果今天我決定要用 JS 來寫一個動畫效果,當使用者按下網頁的按鈕之後,把本來的文字更改為「按下按鈕囉!」,要怎麼寫。

但是最關鍵的一步:怎樣讓電腦因為我按下按鈕而做出反應,卻沒有提到。今天就讓我們繼續深入探索這一塊吧!

事件流程

想像今天有一個球丟過來,你可能會選擇接住它(或是躲開)。除非你可以預知未來,不然應該不太會有你已經先躲開,才有球飛過來的事情吧。對電腦來說也一樣,你丟給它一個事件,它收到以後去執行相對應的事情。

我們昨天有提到 HTML Dom 的架構樹。讓我們一邊回想昨天的架構樹,一邊思考一下這蛋生雞雞生蛋的問題:當我點擊按鈕的時候,事件是從按鈕的 <button> 一路傳遞到上面的<body><head><document> ,還是要從<document> 一路傳下來呢?

其實這兩種都會執行。

<document> 一路傳到最底層,順序由上而下,我們稱呼為事件捕獲 Event Capturing。反之,順序由下而上的,我們稱呼為事件冒泡 Event Bubbling。用下面這張圖會比較清楚:

當我點擊的物件有父層(物件本身是子層),順序依序為:

點子層>父捕獲>子捕獲>子冒泡>父冒泡。

當我點擊的物件本身就是父層時,順序依序為:

點父層>父捕獲>父冒泡。

事件處理

當我們要讓電腦收到事件,做出對應事項,有好幾種做法,其中一種,是在 html 標籤後面放事件處理程式碼,也就是「on + 事件名稱 = "要做的事情"」。

舉例來說有這幾種:

  • onclick 點擊某區
  • onmouseover 滑鼠移到某區
  • onmouseout 滑鼠移出某區
  • onload 自動偵測是否已 load 完

事不宜遲讓我們來使用看看!當滑鼠點擊按鈕時,我要讓它的字變成紅色的。我們可以在 html 裡這樣寫:

<button onclick = "style.color = 'red';">click</button>

這邊的 style.color = 'red' 運用到之前的觀念,不熟的人可以回去讀昨天的文章。

在使用這種方式時要注意幾點:

  1. 請輪流使用雙引號跟單引號:
    就像上面的範例一樣,因為外圍已經包了一層雙引號,裏頭的部分就改用單引號包住。否則電腦會不知道這個雙引號的另一半是哪個雙引號,導致判別錯誤!

  2. 善用 this 來減少程式複雜度,直接在 JS 的地方去定義函式:
    相信大家寫 html 跟 css 時,都會盡量避免直接把 css 寫在 html 裡面,因為可能要重複寫好幾次同樣的東西,而且版面會變得又亂又難閱讀。 JS 也是一樣,雖然 onclick 的詳細設定可以直接寫在 html 裡,但為了避免未來的你穿越到現在砍死你,還是別吧!

要怎麼寫呢?在 html 的部分我們這樣寫:

<span onmouseover = "over(this);" onmouseout = "out(this);"> 移過來移出去顏色不一樣</span>

<div onmouseover = "over(this);" onmouseout = "out(this);"> 移過來移出去,這個顏色也不一樣</div>

在 js 的部分我們這樣寫:

function over(e){
  e.style.color = "red";
}

function out(e){
  e.style.color = "black";
}

發現了嗎?我們重複使用了 over 和 out 這兩個函式,但是不需要每次都寫一次 over 是什麼? out 又是什麼。

this 的概念很難簡單描述完,這邊請先理解成英文代名詞的概念(在 span 的地方 this 代表 span , div 的地方代表 div ),之後會再放上 this 的文章供大家閱讀。

事件監聽 .addEventListener

學會了上面的以後,讓我們來介紹另一種方式吧!

事件監聽的意思是,當我監聽到有事件,就自動去做後面的事情。寫法是把 addEventListener 加在你想要監聽的東西後面,並且告訴他要監聽怎樣的行為,跟執行什麼動作。

用昨天的例子來說,使用者按下網頁的按鈕之後,把本來的文字更改為「按下按鈕囉!」,我們可以這樣理解:

我要告訴電腦要監聽按下的這個行為,並執行把本來的文字更改為「按下按鈕囉!」的動作,要監聽的對象則是按鈕。

html 中我們這樣寫:

<button id = "btnChange">按鈕</button>

JS 中我們這樣寫:

let btnChange = document.getElementById("btnChange");
function change(){
  btnChange.innerHTML = "按下按鈕囉!";
}

btnChange.addEventListener("click",change);

要監聽哪個東西寫最前面,要監聽怎樣的動作,必須用雙引號包住。而逗號後面放的,則是要做什麼對應的函式。

但接下來你可能會勤奮不倦,用 getElementsByClassName 依樣畫葫蘆寫一次,然後就發現...完了,怎樣都是錯誤訊息(崩潰)。這是因為,你的 HTML 中可能有好幾個同樣的 class 名稱,這些會通通被放進陣列裡,你可以這樣改寫程式碼:

let btn = document.getElementsByClassName("btn")[0]; //加[0]選擇第一個DOM元素

function change(){
  btn.innerHTML = "按下按鈕囉!";
}

btn.addEventListener("click",change);

當然也可以使用 forEach 來幫每個元素都加上監聽!使用 document.querySelectorAll 選取所有 class 也會遇到同樣的狀況,解決方法也是一樣的。

以上就是我們今天的學習,是不是很簡單呢?

學習與參考資料

JS 學徒特訓班教學影片及練習題 14 關
事件監聽跟 getElementsByClassName: https://hovertree.com/h/bjaf/e4osnper.htm
HTML DOM getElementsByClassName() 方法: https://www.runoob.com/jsref/met-element-getelementsbyclassname.html


上一篇
08 HTML DOM 、 .innerHTML 、 getElementById 、 getElementsByClassName 與 document.querySelector
下一篇
10 This
系列文
花三十天找到 JavaScript 沙漠中的綠洲35
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言