前端的擷取與冒泡事件
在設計畫面互動的時候,有時候需要撰寫一些事件處理,這邊將介紹其中的原理與在 React 中的一些小知識。
簡單介紹
要專業的處理 event 事件,就必須要了解擷取與冒泡事件,概念簡單但是特別重要。
根據上圖,我們可以看到事件處理主要分為三個階段。
- 擷取階段
- 目標階段
- 冒泡階段
如果你覺得太複雜的話,你可以想像你是一位路跑選手,window 是起點與終點,目標是轉則點,你的目標是蒐集事件,而事件又分為冒泡事件和擷取事件,如果他是擷取事件,那你應該是在抵達轉折點之前蒐集,如果是冒泡事件則是在轉折之後蒐集。
理解這個概念之後就可以開始認識擷取與冒泡了。
DOM 元素事件
addEventListener 的第二個參數可以控制這個參數是屬於擷取還是冒泡事件,如果標記這個事件屬於擷取事件,那麼這個 EventListener 就會在擷取階段被 trigger。
1 | <form> |
React 元素事件
DOM element 與 React element 的事件處理是兩個不一樣卻類似的東西。
主要差異在:
- 事件的名稱在 React 中都是 c,而在 HTML DOM 中則是小寫。
- 事件的值在 JSX 中是一個 function,而在 HTML DOM 中則是一個 string。
SyntheticEvent
React 中的 event 為根據 W3C 定義的 SyntheticEvent,它也包含了瀏覽器的原生事件,例如:stopPropagation。
camelCase
1 | <button onClick={activateLasers}>Activate Lasers</button> |
避免瀏覽器預設行為
DOM element 可以使用 return false 辦到,React 可以使用 preventDefault
1 | function Form() { |
冒泡事件
冒泡顧名思義就是泡泡冒上來的意思,因此是 bottom-up 的方式傳遞事件。
幾乎大部分的事件都是屬於冒泡事件,當一個元素被 trigger 時,自己本身的 event handler 會先觸發,再往上冒泡 trigger parent 的 event handler。
以下以 DOM event 的 onclick 為例解釋冒泡事件:
1 | <!-- |
也就是往上冒泡的過程,甚至可以到最外層的 html,幾乎所有的 parent 都知道你在做什麼了,可是我不想讓 parent 知道我在做什麼
可以使用到 event.stopPropagation() 來停止任何的冒泡和擷取事件傳遞。
但是需要注意是在什麼階段使用它,才能夠妥善達到預期的效果。
擷取事件
在擷取階段的時候,擷取事件會被 trigger。
儘管大部分的事件都屬於冒泡事件,但是我們可以自定義事件為擷取事件,這樣在 top-down 的過程就可以處理需要觸發的事件了。
這邊來介紹一個 React 提供但是很多人不知道的東西,叫做:onClickCapture。
onClick 是在冒泡階段會 trigger 的事件,但是如果你想要在擷取階段 trigger 的話,可以使用:onClickCapture
實作例子
如果你要製作 Card,點擊卡片會開啟新視窗,但是上面又有其他按鈕時,這個時候你就需要針對事件去做處理。
1 | <Card key={card.id} onClick={open("/card", "_blank")}> |
關於 React 的冒泡與擷取事件
因為原生的事件處理有少部分是屬於擷取事件,例如:onfocus, onblur, onchange……
React 為了單一化,讓所有的事件都變成了冒泡事件
像是以下的專案在 React 上執行,你會發現執行之後 onfocus 變成了冒泡事件:
1 | import React from "react"; |
再來一個範例:
1 | import React from "react"; |
在 React17 之後,有一個比較大的更動
17 之前會在 document 運行 document.addEventListener()
17 之後會在 root 運行 rootNode.addEventListener()
(從 debug tools 選取 root 再查看 event litener 就可以看出)
補充資料
- https://javascript.info/bubbling-and-capturing
- https://www.google.com/url?sa=t&rct=j&q=&esrc=s&source=web&cd=&cad=rja&uact=8&ved=2ahUKEwjw9f6w7InyAhXJGaYKHRXRBicQFjABegQIBRAD&url=https%3A%2F%2Fcodesandbox.io%2Fs%2Fju5fz&usg=AOvVaw0dwXidXILLy-e42TMYKUFu
- https://betterprogramming.pub/whats-the-difference-between-synthetic-react-events-and-javascript-events-ba7dbc742294