Event Bubbling Capturing Delegation
β JS β 9 min read
π‘ μ΄ ν¬μ€ν μ μ΄λ²€νΈ λ²λΈλ§/μΊ‘μ³λ§ λν΄ κ³΅λΆνλ©° μ 리ν λ΄μ©μ λλ€. νΉμ¬λ μΌλΆ μ¬λ°λ₯΄μ§ μμ μ λ³΄κ° μμ μμ μ§μ ν΄μ£Όμλ©΄ μ μ ν λ‘νκ² μ΅λλ€.
κ°μ π«
μ΄λ²€νΈ λ²λΈλ§κ³Ό μΊ‘μ³λ§, μμμ λν΄ κ³΅λΆνκ³ , κ°λ¨ν μμ λ₯Ό μμ±ν©λλ€.
μ΄λ² ν¬μ€ν μμλ μ΄λ²€νΈκ° λ°μν λ μΌμ΄λλ νΉμ§μΈ λ²λΈλ§κ³Ό μΊ‘μ³λ§μ λν΄ μ 리νκ³ , μ΄λ²€νΈ μμμ ν΅ν΄ ν¨κ³Όμ μΌλ‘ μΉμ μ μ΄νλ λ°©λ²μ λ€λ£¨κ³ μ νλ€.
Event π

μΆμ² - 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("λ²νΌμ ν΄λ¦νλ€.");};
λ©μλλ₯Ό ν΅ν μ΄λ²€νΈ νΈλ€λ¬ ν λΉ
μ΄λ²€νΈ νλ¦
μ΄λ²€νΈ μΊ‘μ³λ§ -> νκΉ λ¨κ³ -> μ΄λ²€νΈ λ²λΈλ§

μ΄λ²€νΈ λ²λΈλ§ π
μ΄λ²€νΈ λ²λΈλ§μ νΉμ νλ©΄ μμμμ μ΄λ²€νΈκ° λ°μνμ λ ν΄λΉ μ΄λ²€νΈκ° λ μμμ νλ©΄ μμλ€λ‘ μ λ¬λμ΄ κ°λ νΉμ±μ μλ―Ένλ€.
<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
μ μμ λ³κ²½νκ³ μΆλ€λ©΄,
- κ³΅ν΅ μ‘°μμΈ
table
μ μ΄λ²€νΈ νΈλ€λ¬λ₯Ό ν λΉνκ³ - event.targetμ μ΄μ©ν΄ μ΄λ€ μμκ° ν΄λ¦ λμλμ§ κ°μ§νκ³
- ν΄λ¦λ μμκ°
td
κ° μλ μreturn
μν¨λ€. 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 μμ
λΆνκ° λμ΄λ μ μ.
μ΄λ° λΆνλ 무μν λ§ν μμ€μ΄λ―λ‘ μ€μ λ‘λ μ κ³ λ €νμ§ μλλ€κ³ νλ€.