jQuery - 事件處理

事件處理

事件處理是網頁互動行為很重要的核心,通常當一個事件發生時,會去呼叫一個事件處理程序(event handler)的回呼函式,也就是事件發生時要做的事情。jQuery 對事件有許多特別的貼心設定。

事件觸發

要觸發一個事件要有三個步驟,第一個是指定選取對象、第二個是指派事件、第三個是傳遞一個函式,在語意上是誰、在甚麼時候、做了甚麼事情,事件觸發有下列兩種方式。

一、使用事件名稱直接觸發

此方法為便捷方式,是方法二的捷徑,但只能夠用在 DOM 元素已經存在時有作用,在網頁讀取完畢時,若 DOM 元素還不存在,也就是後來產生的 DOM 元素,無法使用。

$('#myElement').click(function () {
alert($(this).text())
})

不帶參數直接呼叫事件。

$('button').click()

二、使用 on()方法觸發

建議使用這種方式,on 方法提供了事件處理程序所有功能,而且語意上與 JavaScript 的 addEventListener() 相似,其實,on 是以 addEventListener 實作,且第三個參數是 false,也就是 jQuery 事件是以「事件冒泡」來實作,而不是「事件捕獲」,這很符合 JavaScript addEventListener 第三參數 useCapture 的預設 false。該方法又分為「直接綁定」與「委派綁定」。

.on(events [, selector ] [, data ], handler)

  • events 可以多個事件,空格分隔事件名稱。
  • 指定 css selector 為委派綁定,參考下方。
  • 指定 data(可以任何資料類型),當事件發生時將通過 event.data 傳遞。

請忘記 bind() 與 live(),on() 都可以做到。

直接綁定

當 selector 省略或是 null,事件處理程序稱為直接綁定,會發生在選定的元素上,也就是呼叫該事件的元素。

$('#myElement').on('click', function () {
alert($(this).text())
})

委派綁定

又稱為事件委派(delegation),當提供 selector 參數時,事件處理程序稱為委派綁定。事件不被綁定元素所使用,而只對綁定元素的後代 selector 使用,委派事件綁定的優勢在於可以處理來自後代元素的事件,也就是程式後來產生的後代 DOM 元素

委託事件處理程序不適用於SVG。

多事件觸發

on 可以使用多種事件觸發,以下 click,keypress 都會觸發不具名函式:

$(document).on('click keypress', function () {
$('#lightBox').hide()
})

移除事件

可以使用 off() 來移除事件,要移除元素的所有事件,不要傳任何參數給 off()函式,這是殺傷力很強的方式,大部分情況下不會移除元素所有的事件處理程序。

$('input[type="submit"]').off()

也可以指定移除的事件。

$('h1').each(function () {
$(this).off('click')
})

named space 命名空間移除特定目標的事件,可以為事件命名一個名字,這樣移除時可以指定該名稱。

$('#box').on('click.main', function () {
alert('click1')
})

$('#box').on('click.sub', function () {
alert('click2')
})

// 移除 sub

$('#box').off('click.sub')

事件類型

分類 事件名稱
鍵   盤 keydown,keyup,keypress
滑   鼠 click,dblclick,hover,mousedown,mouseenter,mouseleave,mouseup,,mousemove,mouseout,mouseover,toggle
表   單 blur,change,focus,focusin,focusout,select,submit,reset
瀏 覽 器 error,resize,scroll
文   件 load,unload,ready

載入事件

名稱 常用 說明
.ready() DOM 載入完成後(不等待其他資源載入),ready 就觸發

瀏覽器事件(Browser Events)

與瀏覽器事件有關的設定 說明
.resize() 設定瀏覽器視窗大小改變時執行的處理
.scroll() 設定瀏覽器視窗被捲動時執行的處理

滑鼠事件(Mouse Events)

與滑鼠動作有關的設定 說明
.click() 設定元素被點擊時執行的處理
.dblclick() 設定元素被滑鼠雙擊時執行的處理
.hover() 設定元素移入、移出時執行的處理
.mouseover() 設定滑鼠停在元素上時執行的處理
.mouseout() 設定滑鼠移出元素上時執行的處理
.mouseenter() 設定滑鼠停在元素上時執行的處理 (包含範圍內的子元素)
.mouseleave() 設定滑鼠移出元素上時執行的處理 (包含範圍內的子元素)
.mousedown() 設定元素被按下時執行的處理
.mousemove() 設定滑鼠在元素上方移動時執行的處理
.mouseup() 設定滑鼠離開元素上方時執行的處理

## 表單事件(Form Events)

與表單事件有關的設定。 說明
.change() 當表單元素內容改變時執行的處理
.focus() 當表單元素取得焦點時執行的處理
.focusin() 當表單元素取得焦點時執行的處理 (包含子元素)
.blur() 當焦點離開表單元素時執行的處理
.focusout() 當焦點離開表單元素時執行的處理 (包含子元素)
.select() 表單元素的值被選取時執行的處理
.submit() 送出表單資料時執行的處理

鍵盤事件(Keyboard Events)

與鍵盤輸入有關的設定 說明
.keydown() 按下鍵盤按鈕時執行的處理
.keypress() 鍵盤輸入時執行的處理
.keyup() 放開鍵盤按鈕時執行的處理

事件應用

hover 事件

hover 是常使用的滑鼠事件,它是由 mouseenter 與 mouseleave 來實作,可由 e.type 確認,它可以傳入兩個匿名函式分別給 mouseenter 與 mouseleave 使用。如果只傳入一個引數給 hover(),那個函式會同時被用作 mouseenter 與 mouseleave 事件的處理器。

.hover(handlerIn, handlerOut)

$('a').hover(
function (e) {
console.log(e.type)
},
function (e) {
console.log(e.type)
}
)

兩種滑鼠移入、移出的操作,第一種說明了 on 也可以物件實字來操作多種事件

// 第一種用 on 並傳入一個選項物件
$('img').on({
mouseover: function () {
$(this).stop().fadeTo(3000, 0.1)
},
mouseout: function () {
$(this).stop().fadeTo(3000, 1)
}
})

// 第二種用 hover(),使用兩個參數
$('img').hover(
function () {
$(this).stop().fadeTo(3000, 0.1)
},
function () {
$(this).stop().fadeTo(3000, 1)
}
)

事件物件

事件物件(event object),當一個或多集合 jQuery 物件觸發事件時,會記錄著該物件包含與該次事件有關的資訊屬性與方法,被稱為事件物件(Event Object),它會被帶入第一參數,通常以 e 作為參數名稱。事件物件主要基於 W3C 的標準,也結合了業界的事件標準,jQuery 從原生的 JavaScript Event 物件中複製了常用屬性到每個 jQuery Event 物件中,因此屬性、方法名稱一樣,但對某些特定事件類型來說,其中部分屬性的值會是 undefined

$(document).on('click', function (e) {
console.log(e) // 事件物件
})

e.target

event.target 屬性即實際被點擊的元素,可以記為最深處的目標,儲存著發生事件的目標元素,透過這個屬性可以確定 DOM 中首先接收到事件的元素。而且,this 引用的是處理事件的 DOM 元素,藉由 event.target 與 this 比對,可以做出以下的判斷。

$('#switcher').click(function (event) {
if (event.target == this) {
$('#switcher'.button).toggleClass('hidden')
}
})

或者是當 event.target 是 a 時忽略。

if ($(event.target).is('a')) return // 忽略發生於連結上的事件

e.currentTarget

currentTarget 屬性指出哪個元素註冊了事件,永遠與 this 相同。如果 target 與 currentTarget 不同,表示所處理的事件就是自其發生處產生氣泡上浮後的事件,可以透過 is()方法來測試 target 元素。

e.relatedTarget

對於 mouseout 事件,它指向被進入的元素,對於 mouseover 事件,它指向被離開的元素。

e.clientX、e.clientY

事件觸發時,返回滑鼠相對瀏覽器可視區域左上角的偏移量,固定不隨頁面而改變,可視區域不包括工具欄和滾動條。兼容性:所有瀏覽器均支持。

e.pageX、e.pageY

事件觸發時,滑鼠游標到 document 文件左上角的偏移量,會隨著頁面卷軸滾動而改變,這 2 個屬性雖不是標準屬性,但得到了廣泛支持,除了 IE6/7/8。

e.offsetX、e.offsetY

事件觸發時,滑鼠游標相對父元素左上角的偏移量,左上角的基準點在不同瀏覽器各有不同,IE 以內容區左上角為基準點不包括邊框。Chrome 以邊框左上角為基準點。

e.screenX、e.screenY

事件觸發時,滑鼠游標相對於螢幕顯示器螢幕左上角的 X,Y 坐標。

$(document).on('click', function (e) {
console.log('e.clientX', e.clientX, 'e.clientY', e.clientY)
console.log('e.pageX', e.pageX, 'e.pageY', e.pageY)
console.log('e.offsetX', e.offsetX, 'e.offsetY', e.offsetY)
console.log('e.screenX', e.screenX, 'e.screenY', e.screenY)
})

e.preventDefault()

阻止瀏覽器事件預設回應的函式,此函式是事件物件的一部分,可以在事件處理函式內存取。若網頁有個連結,點擊連結時通常瀏覽器會連結到該網址,如果要阻止它的預設行為。當在事件的環境中完成了某些作用,例如頁面滾動到錨點 id 的位置,通常會用到 e.preventDefault()。

$('a').click(function (e) {
e.preventDefault() // 連結無作用
})

也可以寫成以下這樣:

$('#menu').click(function () {
return false //事件不會發生
})

event.stopPropagation()

阻止事件冒泡,event.stopPropagation() 可以阻止 click 事件冒泡到父元素,透過呼叫 event.stopPropagation() 就可以避免其他所有 DOM 元素回應這個事件。點擊按鈕的事件會被按鈕處理,而且只會被按鈕處理。

$('#theLink').click(function (e) {
e.stopPropagation()
})

鍵盤事件的事件物件屬性

鍵盤事件 解說
keyCode 當 keypress 事件時,返回 character code;當 keydown 或 keyup 事件時,返回 key code
which 當按下滑鼠按鍵,取得是哪個按鍵,值同 keyCode
charCode 當 keypress 事件時,返回 character code
altKey 布林值 (boolean),用來判斷使用者是否有按 alt 鍵
ctrlKey 布林值 (boolean),用來判斷使用者是否有按 ctrl 鍵
shiftKey 若事件發生時 shift 按著則為 true;
metaKey 布林值 (boolean),用來判斷使用者是否有按 meta 鍵
  • metaKey
    若是原生的事件物件沒有 metaKey 屬性,jQuery 會將此設為與 ctrlKey 屬性相同的值。MacOS 中會是 Command 鍵設定 metaKey 屬性。

  • which

    jQuery 正規化(normalize)這個非標準事件屬性,指出在事件中按下了哪個滑鼠鍵或鍵盤按鍵。
    對鍵盤事件來說,若是原生的事件沒有定義 which,但定義了 charCode 或 keyCode,which 會被設為這些屬性所定義的值。
    對滑鼠事件來說,若是 which 無定義,但 button 屬性有定義,which 會依據 button 的值來設定。

    0 代表沒有按下任何滑鼠按鍵。
    1 代表按下左鍵。
    2 代表按下中鍵。
    3 代表按下右鍵。(某些瀏覽器不會為右鍵點擊產生滑鼠事件)

ASCII character 對照表
Key codes 對照表

其他事件物件屬性

常用 解說
type 返回事件類型,例如 “click”
timeStamp 事件發生時的時間 timestamp (單位是 milliseconds 毫秒)
eventPhase 返回為一個數字,表示事件處於目前所處的傳播狀態 (event flow)
有這些值:0: None,1: capturing phase。2: target phase,3: bubbling phase
data 用於 on()函式傳遞資料給事件處理函式的 jQuery 物件。
  • timeStamp
    事件發生的時間點,格式為 Date.getTime()方法所回傳那樣,單位式毫秒。jQuery 會自行設定這個屬性,以避開 FireFox 一個存在已久的臭蟲。

事件旅行

事件旅行指的是事件傳遞的順序,分為「事件捕獲」、「事件冒泡」兩種,也就是 HTML 層級間若有事件存在,那麼點擊某一個元素,會依據這兩種其中一種方式來傳遞事件。而在 jQuery 裡面, 已經將 addEventListener 的第三參數設定為 false,也就是「事件冒泡」,所以事件傳遞會由內而外。

事件捕獲(event capturing)

事件傳遞會由外而內,addEventListener 第三參數為 true。

事件冒泡(event bubbling)

事件傳遞會由內而外,addEventListener 第三參數為 false。

事件冒泡範例

點擊「我是最裡面」,傳遞會由 a > inner > outer > document。a 設定 e.preventDefault()因此連結會無效,若再設定 e.stopPropagation() 可以阻止事件冒泡傳遞,就不會觸發其他事件。

<style>
html,
body {
height: 100%;
}

body {
display: flex;
justify-content: center;
align-items: center;
}

.outer {
width: 400px;
height: 400px;
background: #333;
display: flex;
justify-content: center;
align-items: center;
}

.inner {
width: 50%;
height: 50%;
background: #777;
display: flex;
justify-content: center;
align-items: center;
}

a {
width: 50%;
height: 50%;
color: #333;
background: #eee;
display: flex;
justify-content: center;
align-items: center;
}
</style>
<div class="outer">
<div class="inner">
<a href="http://www.example.com">我是最裡面</a>
</div>
</div>

<script>
document.addEventListener('click', function (e) {
console.log('document')
})

document.querySelector('.outer').addEventListener('click', function (e) {
console.log('outer')
})

document.querySelector('.inner').addEventListener('click', function (e) {
console.log('inner')
})

document.querySelector('a').addEventListener('click', function (e) {
e.preventDefault() // 連結預設無效
e.stopPropagation() // 阻止事件冒泡傳遞
console.log('a')
})
</script>