到了,叫我。
瀏覽器的事件處理很像我們日常生活中會發生的事,針對某些目標,一旦有情況發生,就執行相對應的程序。
就像買票去墾丁,我們(對象目標)一旦到達墾丁(情況發生),我們就會下車(執行程序)。
Event Binding
針對瀏覽器,使用者觸發的行為( 例如 mousemove 或 click ) 或是系統自行觸發的行為 ( 例如 load ),我們稱這些行為為事件(event),並且可以對這些事件註冊事件處理器(event handler),當監聽的事件一旦發生,就執行對應的 event handler。
- event 其實是物件,有各種 property 及 method 可以使用
- event handler 就是 function,即我們要執行的程式碼
以下我們來分別使用 javascript 及 jQuery 寫出一個範例,當使用者在螢幕按下滑鼠時,會在瀏覽器發開者工具的頁面看見輸出 hello world
,以下為分別的角色:
- window: 目標
- click: 監聽的事件
- sayHello: 事件處理器
|
|
|
|
將此觀念擴展並實作後,我們可以指定目標,針對目標設定需要監聽事件,並為這些事件註冊事件處理器。一旦目標所監聽的事件發生,就執行事件處理器。
Event Capturing and Bubbling
在談論 event delegation 之前,我們先來了解事件( event )是如何在 DOM tree 傳遞。
以下面的 dom 為例子,當我們用滑鼠按了 click me
的按鈕,click 事件便開始在 dom 之間傳遞,直到事件完成 1 個 cycle,結束事件的傳遞。
事實上,事件的傳遞可分為 3 個部分:
- capturing: 由外圍開始向 target 傳遞事件,在這個例子即為
- wrapper1 => wrapper2 => wrapper3 => target
- target: 驅動這個事件的目標,在這個例子即為
<button class="target">click me</button>
- bubbling: 由target開始向外圍傳遞事件,在這個例子即為
- target => wrapper3 => wrapper2 => wrapper1
整體來看的概念如以下所示:
- capturing + target + bubbling
- wrapper1 => wrapper2 => wrapper3 => target => wrapper3 => wrapper2 => wrapper1
|
|
javascript 預設的事件處理為 event bubbling,原因在此不贅述,簡單的說,事件的傳遞在 capturing 階段不執行任何的 event handler,直到事件傳遞到 target 及 bubbling 階段,才針對監聽的事件,執行 event handler。
根據以下的程式碼範例,我們可以看見事件傳遞階段會依序發生的事:
- capturing 階段
- wrapper1: 未執行 event hanlder
- wrapper2: 未執行 event hanlder
- wrapper3: 未執行 event hanlder
- target 階段
- target: ‘this is target’
- bubbling 階段
- wrapper3: ‘this is wrapper3’
- wrapper2: ‘this is wrapper2’
- wrapper1: ‘this is wrapper1’
|
|
|
|
Event Delegation
Event Delegation 即事件代理,在討論實作之前,我們先針對以下的需求,寫出相對應的程式碼。
需求: 當使用按了 list
元素,在 browser dev tool 輸出 list
中的文字
|
|
|
|
|
|
由上述的程式碼,我們可以看出針對每個 list
node 設定監聽 click 的事件,當事件發生時,會執行 event hanlder 的內容,即在 browser dev tool 輸出 list
中的文字。
但是在某些常見的情況,上述的解法會有效能問題或無法實作的情況:
list
node 有很多時,例如有 50 個,我們必須對這 50 個list
node 分別進行 event binding,相當於同時監聽 50 個 node,造成質性效能不佳。- 動態產生的
list
node 沒有被加入到當初的 event binding,相當於不符合之前的需求。
上述的情況可以由 evnet delegation 幫我們解決,由於 event 具有 bubbling 的特性,因此針對槽狀的 html 結構,並不需要一一為內部 dom node 綁定事件,而是可以只需在外圍的 dom node 綁定事件,一旦事件觸發時,直到事件 bubble 至外圍的 dom node時,才執行 event hanlder。
以下為改善之前的例子而使用 event delegatin 的程式碼。
|
|
|
|