Skip to content
TASK ORIENTED
LinkedInGithub

Event Bubbling Capturing Delegation

β€” JS β€” 9 min read

πŸ’‘ 이 ν¬μŠ€νŒ…μ€ 이벀트 버블링/캑쳐링 λŒ€ν•΄ κ³΅λΆ€ν•˜λ©° μ •λ¦¬ν•œ λ‚΄μš©μž…λ‹ˆλ‹€. ν˜Ήμ—¬λ‚˜ 일뢀 μ˜¬λ°”λ₯΄μ§€ μ•Šμ€ 정보가 μžˆμ„ μ‹œμ— μ§€μ ν•΄μ£Όμ‹œλ©΄ μ •μ •ν† λ‘ν•˜κ² μŠ΅λ‹ˆλ‹€.

κ°œμš” πŸ›«

이벀트 버블링과 캑쳐링, μœ„μž„μ— λŒ€ν•΄ κ³΅λΆ€ν•˜κ³ , κ°„λ‹¨ν•œ 예제λ₯Ό μž‘μ„±ν•©λ‹ˆλ‹€.

이번 ν¬μŠ€νŒ…μ—μ„œλŠ” μ΄λ²€νŠΈκ°€ λ°œμƒν•  λ•Œ μΌμ–΄λ‚˜λŠ” νŠΉμ§•μΈ 버블링과 캑쳐링에 λŒ€ν•΄ μ •λ¦¬ν•˜κ³ , 이벀트 μœ„μž„μ„ 톡해 효과적으둜 웹을 μ œμ–΄ν•˜λŠ” 방법을 λ‹€λ£¨κ³ μž ν•œλ‹€.


Event πŸŽƒ

event_handler

좜처 - https://www.toolsqa.com/javascript/event-handlers-in-javascript/

이벀트(event)λŠ” λͺ¨λ“  DOM λ…Έλ“œμ—μ„œ λ§Œλ“€μ–΄λ‚Ό 수 μžˆλŠ” μ‹ ν˜Έμ΄λ‹€.

<button>λ²„νŠΌ</button>

μœ μ €κ°€ μœ„ λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ λ²„νŠΌ νƒœκ·ΈλŠ” click 이벀트λ₯Ό λ°œμƒ μ‹œν‚¨λ‹€.

μš°λ¦¬λŠ” μœ„μ™€ 같이 DOM λ…Έλ“œμ—μ„œ μ΄λ²€νŠΈκ°€ λ°œμƒν•  λ•Œ νŠΉμ • ν•¨μˆ˜λ₯Ό μž‘λ™μ‹œν‚¬ 수 μžˆλŠ”λ°, κ·Έ ν•¨μˆ˜λ₯Ό ν•Έλ“€λŸ¬(handler) λΌκ³ ν•œλ‹€.

ν•Έλ“€λŸ¬λ₯Ό ν• λ‹Ήν•˜λŠ” 방법은 μ•„λž˜μ™€ 같이 μ„Έ κ°€μ§€κ°€ μžˆλ‹€.

  • HTML 속성: onclick="...".
  • DOM ν”„λ‘œνΌν‹°: elem.onclick = function.
  • λ©”μ„œλ“œ: elem.addEventListener(event, handler[, phase])둜 ν•Έλ“€λŸ¬λ₯Ό μΆ”κ°€ν•˜κ³ , removeEventListener 둜 ν•Έλ“€λŸ¬λ₯Ό μ œκ±°ν•¨

HTML 속성을 μ΄μš©ν•œ 이벀트 ν•Έλ“€λŸ¬ 할당은 자주 쓰이지 μ•ŠλŠ”λ‹€.

  • κΈ΄ μ½”λ“œλ₯Ό λΌμ›Œ λ„£λŠ” 게 λΆˆκ°€λŠ₯ν•˜λ‹€.

DOM ν”„λ‘œνΌν‹°λ₯Ό μ‚¬μš©ν•œ 방법은 쓰일 수 μžˆλ‹€.

  • μ—¬λŸ¬ ν•Έλ“€λŸ¬ 할당이 λΆˆκ°€λŠ₯ν•˜λ‹€λŠ” 단점이 μžˆλ‹€.

λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 방법이 κ°€μž₯ μœ μ—°ν•˜λ‹€.

  • transitionend와 DOMContentLoaded 같은 일뢀 μ΄λ²€νŠΈλŠ” 이 λ°©λ²•μœΌλ‘œλ§Œ μ²˜λ¦¬ν•  수 μžˆλ‹€.
document.querySelector("button").addEventListener("click", handler);
const handler = () => {
alert("λ²„νŠΌμ„ ν΄λ¦­ν–ˆλ‹€.");
};

λ©”μ„œλ“œλ₯Ό ν†΅ν•œ 이벀트 ν•Έλ“€λŸ¬ ν• λ‹Ή

이벀트 흐름

이벀트 캑쳐링 -> 타깃 단계 -> 이벀트 버블링

event_flow

이벀트 버블링 πŸ›

이벀트 버블링은 νŠΉμ • ν™”λ©΄ μš”μ†Œμ—μ„œ μ΄λ²€νŠΈκ°€ λ°œμƒν–ˆμ„ λ•Œ ν•΄λ‹Ή μ΄λ²€νŠΈκ°€ 더 μƒμœ„μ˜ ν™”λ©΄ μš”μ†Œλ“€λ‘œ μ „λ‹¬λ˜μ–΄ κ°€λŠ” νŠΉμ„±μ„ μ˜λ―Έν•œλ‹€.

123Most deeply nested element
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>

μœ„ μ½”λ“œμ—μ„œ p νƒœκ·Έλ₯Ό ν΄λ¦­ν•˜λ©΄

  • <p>에 ν• λ‹Ήλœ onclick ν•Έλ“€λŸ¬κ°€ λ™μž‘.
  • λ°”κΉ₯의 <div>에 ν• λ‹Ήλœ ν•Έλ“€λŸ¬κ°€ λ™μž‘.
  • κ·Έ λ°”κΉ₯의 <form>에 ν• λ‹Ήλœ ν•Έλ“€λŸ¬κ°€ λ™μž‘.

거의 λͺ¨λ“  μ΄λ²€νŠΈλŠ” 버블링 λœλ‹€. focus μ΄λ²€νŠΈμ™€ 같이 버블링 λ˜μ§€ μ•ŠλŠ” μ΄λ²€νŠΈκ°€ μžˆλ‹€.

버블링 쀑단: event.stopPropagation()

이벀트λ₯Ό μ²˜λ¦¬ν•œ λ’€ 버블링을 μ€‘λ‹¨ν•˜λŠ” λͺ…λ Ή.

버블링 쀑단을 λ‚¨μš©ν•΄μ„œλŠ” μ•ˆλœλ‹€. 예λ₯Ό λ“€μ–΄..

μœ μ € 행동 νŒ¨ν„΄μ„ λΆ„μ„ν•˜λŠ” μ‹œμŠ€ν…œμ„ λ„μž…ν•˜λŠ” λ“±, document의 전체 클릭 이벀트λ₯Ό 감지해야할 λ•Œ 버블링이 μ€‘λ‹¨λ˜μ–΄μžˆλŠ” μƒμœ„ μš”μ†Œλ“€μ€ 죽은 μ˜μ—­μ΄ λœλ‹€.


이벀트 캑쳐링 πŸ’‘

이벀트 μΊ‘μ³λŠ” 이벀트 버블링과 λ°˜λŒ€ λ°©ν–₯으둜 μ§„ν–‰λ˜λŠ” 이벀트 μ „νŒŒ 방식이닀. μƒμœ„μ—μ„œ 더 ν•˜μœ„μ˜ μš”μ†Œλ“€λ‘œ μ „λ‹¬λœλ‹€.

<form>FORM
<div>DIV
<p>P</p>
</div>
</form>
<script>
for(let elem of document.querySelectorAll('*')) {
elem.addEventListener("click", e => alert(`캑쳐링: ${elem.tagName}`), true);
}
</script>

μœ„ μ½”λ“œμ—μ„œ form νƒœκ·Έλ₯Ό ν΄λ¦­ν•˜λ©΄

  • <form>에 ν• λ‹Ήλœ ν•Έλ“€λŸ¬κ°€ λ™μž‘.
  • μ•ˆμͺ½μ˜ <p>에 ν• λ‹Ήλœ onclick ν•Έλ“€λŸ¬κ°€ λ™μž‘.
  • μ•ˆμͺ½μ˜ <div>에 ν• λ‹Ήλœ ν•Έλ“€λŸ¬κ°€ λ™μž‘.

버블링과 λ°˜λŒ€λ‘œ μƒμœ„ μš”μ†Œκ°€ λ“€μ–΄κ°€λ©° μ•„λž˜ 이벀트 ν•Έλ“€λŸ¬λ“€μ„ μ‹€ν–‰μ‹œν‚¨λ‹€.

캑쳐링 λ‹¨κ³„μ—μ„œ 이벀트λ₯Ό μž‘μ•„λ‚΄λ €λ©΄ addEventListener의 capture μ˜΅μ…˜μ„ true둜 μ„€μ •ν•΄μ•Ό ν•œλ‹€.

document.addEventListener("click", handlar, true);

이벀트 캑쳐링은 잘 μ‚¬μš©λ˜μ§€ μ•ŠλŠ”λ‹€. μ΄μœ λŠ” μƒμœ„ μš”μ†Œμ—μ„œ ν•˜μœ„ μš”μ†Œλ‘œ μ΄λ²€νŠΈκ°€ μ „νŒŒλ˜λŠ” 것 보닀 ν•˜μœ„ μš”μ†Œμ—μ„œ μƒμœ„ μš”μ†Œλ‘œ μ „νŒŒλ˜λŠ” 것(버블링)이 더 λ§Žμ€ 정보λ₯Ό κ°€μ§€κ³  있기 λ•Œλ¬Έμ΄λ‹€.


이벀트 μœ„μž„ πŸŽ“

이벀트 μœ„μž„μ€ 캑처링과 버블링을 ν™œμš©ν•œ κ°•λ ₯ν•œ 핸듀링 νŒ¨ν„΄μ΄λ‹€.

곡톡 쑰상에 ν•Έλ“€λŸ¬λ₯Ό ν• λ‹Ήν•˜κ³ , event.target으둜 μ‹€μ œλ‘œ μ–΄λ””μ„œ μ΄λ²€νŠΈκ°€ λ°œμƒν–ˆλŠ”μ§€ μ•Œ 수 μžˆλ‹€.

ref: Modern Javascript tutorial

μœ„ 예제 μ½”λ“œμ—μ„œ 클릭된 td의 색을 λ³€κ²½ν•˜κ³  μ‹Άλ‹€λ©΄,

  1. 곡톡 쑰상인 table에 이벀트 ν•Έλ“€λŸ¬λ₯Ό ν• λ‹Ήν•˜κ³ 
  2. event.target을 μ΄μš©ν•΄ μ–΄λ–€ μš”μ†Œκ°€ 클릭 λ˜μ—ˆλŠ”μ§€ κ°μ§€ν•˜κ³ 
  3. 클릭된 μš”μ†Œκ°€ tdκ°€ 아닐 μ‹œ return μ‹œν‚¨λ‹€.
  4. tdκ°€ λ§žλ‹€λ©΄ event.target.classList의 클래슀 μ‘°μ •μœΌλ‘œ μƒνƒœλ₯Ό λ°”κΎΌλ‹€.

이벀트 μœ„μž„ ν™œμš© πŸ”§

event.target으둜 μ²˜λ¦¬ν•˜λŠ” 방법도 μžˆμ§€λ§Œ, data-actionκ³Ό 같은 속성을 μΆ”κ°€ν•΄λŠ” 방법도 μžˆλ‹€.

data-action

data-action에 ν• λ‹Ήν•œ λ¬Έμžμ—΄μ„ ν•¨μˆ˜λ‘œ κ΅¬ν˜„ν•΄ 이벀트λ₯Ό λ°œμƒμ‹œν‚¬ 수 μžˆλ‹€.

<div id="menu">
<button data-action="save">μ €μž₯ν•˜κΈ°</button>
<button data-action="load">뢈러였기</button>
<button data-action="search">κ²€μƒ‰ν•˜κΈ°</button>
</div>
<script>
class Menu {
constructor(elem) {
this._elem = elem;
elem.onclick = this.onClick.bind(this); // (*)
}
save() {
alert('μ €μž₯ν•˜κΈ°');
}
load() {
alert('뢈러였기');
}
search() {
alert('κ²€μƒ‰ν•˜κΈ°');
}
onClick(event) {
let action = event.target.dataset.action;
if (action) {
this[action]();
}
};
}
new Menu(menu);
</script>

data-counter

λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ μˆ«μžκ°€ μ¦κ°€ν•˜λŠ” 행동을 λΆ€μ—¬ν•΄μ£ΌλŠ” 속성인 data-counterκ°€ μžˆλ‹€.

첫 번째 μΉ΄μš΄ν„°: <input type="button" value="1" data-counter>
두 번째 μΉ΄μš΄ν„°: <input type="button" value="2" data-counter>
<script>
document.addEventListener('click', function(event) {
if (event.target.dataset.counter != undefined) { // 속성이 μ‘΄μž¬ν•  경우
event.target.value++;
}
});
</script>

toggler

data-toggle-id 속성이 μžˆλŠ” μš”μ†Œλ₯Ό ν΄λ¦­ν•˜λ©΄ 속성값이 id인 μš”μ†Œλ₯Ό λ‚˜νƒ€κ±°λ‚˜ μ‚¬λΌμ§€κ²Œν•  수 μžˆλ‹€.

<button data-toggle-id="subscribe-mail">
λ²„νŠΌ
</button>
<form id="subscribe-mail" hidden>
ν† κΈ€ μš”μ†Œ
</form>
<script>
document.addEventListener('click', function(event) {
let id = event.target.dataset.toggleId;
if (!id) return;
let elem = document.getElementById(id);
elem.hidden = !elem.hidden;
});
</script>

이벀트 μœ„μž„μ˜ μž₯/단점

이벀트 μœ„μž„μ˜ μž₯점:

  • λ§Žμ€ ν•Έλ“€λŸ¬λ₯Ό ν• λ‹Ήν•˜μ§€ μ•Šμ•„λ„ 되기 λ•Œλ¬Έμ— λ©”λͺ¨λ¦¬ μ΅œμ ν™”μ— 도움이 λœλ‹€.
  • μš”μ†Œλ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ μ œκ±°ν•  λ•Œ ν•΄λ‹Ή μš”μ†Œμ— ν• λ‹Ήλœ ν•Έλ“€λŸ¬λ₯Ό μΆ”κ°€ν•˜κ±°λ‚˜ μ œκ±°ν•  ν•„μš”κ°€ μ—†κΈ° λ•Œλ¬Έμ— μ½”λ“œκ°€ μ§§μ•„μ§„λ‹€.
  • innerHTMLκ³Ό 같은 λ©”μ„œλ“œλ‘œ μš”μ†Œλ₯Ό λ”ν•˜κ±°λ‚˜ λΊ„ 수 있기 λ•Œλ¬Έμ— DOM μˆ˜μ •μ΄ μžμœ λ‘­λ‹€.

이벀트 μœ„μž„μ˜ 단점:

  • 이벀트 μœ„μž„μ„ μ‚¬μš©ν•˜λ €λ©΄ μ΄λ²€νŠΈκ°€ λ°˜λ“œμ‹œ 버블링 λ˜μ–΄μ•Ό ν•˜μ§€λ§Œ, 버블링 λ˜μ§€ μ•ŠλŠ” μ΄λ²€νŠΈλ“€μ΄ μžˆλ‹€.
  • event.stopPropagation()λ₯Ό μ“Έ 수 μ—†λ‹€.
  • λΆ€λͺ¨μ— ν• λ‹Ήλœ ν•Έλ“€λŸ¬κ°€ λͺ¨λ“  ν•˜μœ„ μ»¨ν…Œμ΄λ„ˆμ—μ„œ λ°œμƒν•˜λŠ” μ΄λ²€νŠΈμ— 응닡해야 ν•˜λ―€λ‘œ CPU μž‘μ—… λΆ€ν•˜κ°€ λŠ˜μ–΄λ‚  수 있. 이런 λΆ€ν•˜λŠ” λ¬΄μ‹œν• λ§Œν•œ μˆ˜μ€€μ΄λ―€λ‘œ μ‹€μ œλ‘œλŠ” 잘 κ³ λ €ν•˜μ§€ μ•ŠλŠ”λ‹€κ³  ν•œλ‹€.

References πŸ™πŸ½

Β© 2024 by TASK ORIENTED. All rights reserved.
Theme by LekoArts