JavaScript์˜ ์ด๋ฒคํŠธ ์ „ํŒŒ (์ด๋ฒคํŠธ ์บก์ณ๋ง, ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง) ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ ์œ„์ž„

October 17, 2021 โ€ข โšก๏ธโšก๏ธโšก๏ธ 13 min read

์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๋‹ค์–‘ํ•œ ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ๋Š” event ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜๊ณ , ์ƒ์„ฑ๋œ event ๊ฐ์ฒด๋Š” ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ์˜ ์ฒซ ๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ์ „๋‹ฌ๋œ๋‹ค. event ๊ฐ์ฒด ๋‚ด๋ถ€์—๋Š” ๋‹ค์–‘ํ•œ ํ”„๋กœํผํ‹ฐ๋“ค์ด ์กด์žฌํ•˜์ง€๋งŒ, ๊ทธ ์ค‘ ๋‹จ์—ฐ ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” ํ”„๋กœํผํ‹ฐ๋ฅผ ๋งํ•ด๋ณด์ž๋ฉด event.target์ด ์•„๋‹๊นŒ ์‹ถ๋‹ค.

์šฐ์—ฐํžˆ event.target๊ณผ event.currentTarget์˜ ์ฐจ์ด์— ๋Œ€ํ•ด ์กฐ์‚ฌ๋ฅผ ํ•˜๊ฒŒ ๋˜์—ˆ๋Š”๋ฐ, ์ด ๊ณผ์ •์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ์–ด๋–ค ๋ฐฉ์‹์œผ๋กœ ์ด๋ฒคํŠธ ํƒ€๊นƒ์— ์ „๋‹ฌ๋˜๋Š”์ง€์— ๋Œ€ํ•œ ์ดํ•ด๊ฐ€ ๋ถ€์กฑํ•˜๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜๋‹ค.

์ด๋ฒˆ ๊ธฐํšŒ์— JavaScript์˜ ์ด๋ฒคํŠธ ์ „ํŒŒ, ์ด๋ฒคํŠธ ์บก์ณ๋ง, ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง, ๊ทธ๋ฆฌ๊ณ  ์ด๋ฒคํŠธ ์œ„์ž„์— ๋Œ€ํ•ด ์กฐ์‚ฌํ•ด๋ณด์•˜๊ณ , ๊ทธ ๋‚ด์šฉ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•ด๋ณธ๋‹ค.

DOM (Document Object Model)

DOM DOM Tree

<!DOCTYPE html>
<html lang="ko">
  <head>
    <meta charset="UTF-8" />
    <title>Title</title>
  </head>
  <body>
    <h1>Welcome</h1>
    <img src="./img.png" alt="My Image" />
    <p>Hello World!</p>
  </body>
</html>

๊ฐ„๋‹จํ•˜๊ฒŒ DOM์— ๋Œ€ํ•ด ์งš๊ณ  ๋„˜์–ด๊ฐ€๋ณด์ž.

DOM(Document Object Model) ์ด๋ž€, ๋ธŒ๋ผ์šฐ์ €์— ๋งˆํฌ์—…๋œ HTML ๋ฌธ์„œ์˜ ๊ฐ์ฒด ๊ธฐ๋ฐ˜ ํ‘œํ˜„ ๋ฐฉ์‹์ด๋‹ค. DOM์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํŠธ๋ฆฌ ๊ณ„์ธต ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง„๋‹ค. ๋ถ€๋ชจ๊ฐ€ ์—†๋Š” ์ตœ์ƒ์œ„ node์ธ root node๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด, root node์˜ ํ•˜์œ„ node์ธ ๋ถ€๋ชจ node๊ฐ€ ์กด์žฌํ•œ๋‹ค. ๋˜ํ•œ ๋ถ€๋ชจ node๋Š” ์ž์‹ node๋ฅผ ๊ฐ€์ง€๋ฉฐ, ์ž์‹ node๊ฐ€ ์—†๋Š” node๋ฅผ leaf node๋ฅผ ๊ฐ€์ง„๋‹ค.

  • Root node: document ๊ฐ์ฒด๊ฐ€ ํ•ด๋‹น๋œ๋‹ค. document ๊ฐ์ฒด๋Š” HTML ์ฝ”๋“œ ์ƒ์—๋Š” ์กด์žฌํ•˜์ง€ ์•Š์ง€๋งŒ, DOM ํŠธ๋ฆฌ์˜ ์ตœ์ƒ์œ„์— ์กด์žฌํ•˜๋ฉฐ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ Œ๋”๋งํ•œ HTML ๋ฌธ์„œ ์ „์ฒด๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” ๊ฐ์ฒด์ด๋‹ค.
  • ๋ถ€๋ชจ node: <html>
  • ์ž์‹ node: <head>, <body>
  • Leaf node: <title>, <meta>, <h1>, <img> ,<p>. (์ž์‹ node๊ฐ€ ์กด์žฌํ•˜์ง€ ์•Š์Œ)

์ด๋ ‡๊ฒŒ DOM์€, root node๋กœ๋ถ€ํ„ฐ leaf node๊นŒ์ง€ ์œ„์—์„œ ์•„๋ž˜๋กœ ์ ์  ๋ป—์–ด๋‚˜๊ฐ€๋Š” ํ˜•ํƒœ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ (Event propagation)

์ด๋ฒคํŠธ ์ „ํŒŒ ์ด๋ฒคํŠธ ์ „ํŒŒ (Event propagation)

(๊ธ€์”จ๊ฐ€ ์‚๋šค๋นผ๋šคํ•œ ์  ์–‘ํ•ด๋ฐ”๋ž๋‹ˆ๋‹ค๐Ÿ™‡โ€โ™€๏ธ)

DOM ํŠธ๋ฆฌ ๋‚ด์— ์กด์žฌํ•˜๋Š” ์š”์†Œ์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด, DOM ํŠธ๋ฆฌ๋ฅผ ํ†ตํ•ด ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ์ „ํŒŒ๋œ๋‹ค. ์ด๊ฒƒ์„ ์ด๋ฒคํŠธ ์ „ํŒŒ (Event propagation) ๋ผ๊ณ  ํ•œ๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ๋Š” ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ์ „ํŒŒ๋˜๋Š” ๋ฐฉํ–ฅ์— ๋”ฐ๋ผ 3๋‹จ๊ณ„๋กœ ๋‚˜๋‰œ๋‹ค.

  1. ์บก์ณ๋ง ๋‹จ๊ณ„ (Capturing Phase): ์ด๋ฒคํŠธ๊ฐ€ ์ƒ์œ„ ์š”์†Œ โ†’ ํ•˜์œ„ ์š”์†Œ ๋ฐฉํ–ฅ์œผ๋กœ ์ „ํŒŒ
  2. ํƒ€๊นƒ ๋‹จ๊ณ„ (Target Phase): ์ด๋ฒคํŠธ๊ฐ€ ์ด๋ฒคํŠธ ํƒ€๊นƒ์— ๋„๋‹ฌ
  3. ๋ฒ„๋ธ”๋ง ๋‹จ๊ณ„ (Bubbling Phase): ์ด๋ฒคํŠธ๊ฐ€ ํ•˜์œ„ ์š”์†Œ โ†’ ์ƒ์œ„ ์š”์†Œ ๋ฐฉํ–ฅ์œผ๋กœ ์ „ํŒŒ

โœ… ์ด๋ฒคํŠธ ์ „ํŒŒ์˜ ๋‹จ๊ณ„๋Š” event.eventPhase ๋กœ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค!

์•„๋ž˜์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋ฉฐ, ์ด๋ฒคํŠธ ์ „ํŒŒ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์žฅ๋ฉด์„ ์‹ค์ œ๋กœ ๊ฒฝํ—˜ํ•ด๋ณด์ž.

CodeSandBox์—์„œ ์ฝ”๋“œ๋ฅผ ๋ผ์ด๋ธŒ๋กœ ์ฒดํ—˜ํ•ด๋ณด๊ธฐ ๐Ÿ”

<div class="redBox">
  <div class="blueBox">
    <button class="button">Button</button>
  </div>
</div>

.redBox๋Š” ๊ฐ€์žฅ ์ƒ์œ„์˜ ๋ถ€๋ชจ ์š”์†Œ, .blueBox๋Š” .redBox์˜ ์ž์‹ ์š”์†Œ์ด๋ฉฐ, .button์€ .blueBox์˜ ์ž์‹ ์š”์†Œ์ด์ž, .redBox์˜ ์†์ž ์š”์†Œ์ด๋‹ค.

.redBox {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 150px;
  height: 150px;
  border: 3px solid red;
  background-color: white;
}

.blueBox {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 100px;
  height: 100px;
  border: 3px solid blue;
  background-color: white;
}

.btn {
  border: 2px solid black;
  border-radius: 5px;
}

default ์ƒํƒœ

๊ฐ๊ฐ์˜ ์š”์†Œ์—๋Š” ์˜์—ญ์„ ๋ช…ํ™•ํžˆ ํ‘œ์‹œํ•˜๊ณ ์ž, border๋ฅผ ์„ค์ •ํ•ด๋‘” ์ƒํƒœ์ด๋‹ค.

const redBox = document.querySelector(".redBox");
const blueBox = document.querySelector(".blueBox");
const button = document.querySelector(".button");
const phases = ["Capturing", "Target", "Bubbling"];

function handleRedBox(event) {
  console.log("Red Box Clicked");
  console.log("Red Box ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "red";
}

function handleBlueBox(event) {
  console.log("Blue Box Clicked");
  console.log("Blue Box ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "blue";
}

function handlebutton(event) {
  console.log("Btn Clicked!");
  console.log("Button ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "black";
  this.style.color = "white";
}

redBox.addEventListener("click", handleRedBox);
blueBox.addEventListener("click", handleBlueBox);
button.addEventListener("click", handlebutton);

์ด๋ฒˆ์—๋Š” JavaScript ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. ๊ฐ Box๋“ค๊ณผ ๋ฒ„ํŠผ์„ querySelector๋ฅผ ์ด์šฉํ•˜์—ฌ ์ทจ๋“ํ–ˆ๊ณ , ๊ฐ ์š”์†Œ์— click ์ด๋ฒคํŠธ๋ฅผ ์„ค์ •ํ•ด๋‘์—ˆ๋‹ค.

.redBox๊ฐ€ ํด๋ฆญ๋˜๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ๋ฐฐ๊ฒฝ์ƒ‰์„ ๋นจ๊ฐ„์ƒ‰์œผ๋กœ, .blueBox๊ฐ€ ํด๋ฆญ๋˜๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ๋ฐฐ๊ฒฝ์ƒ‰์„ ํŒŒ๋ž€์ƒ‰์œผ๋กœ, .button์ด ํด๋ฆญ๋˜๋ฉด ํ•ด๋‹น ์š”์†Œ์˜ ๋ฐฐ๊ฒฝ์ƒ‰์„ ๊ฒ€์ •์ƒ‰์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š” ๊ฐ„๋‹จํ•œ ์ฝ”๋“œ์ด๋‹ค.

๋˜ํ•œ, ๊ฐ ์š”์†Œ๊ฐ€ ํด๋ฆญ๋˜์—ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ณด๋‹ค ๋ช…ํ™•ํžˆ ์บ์น˜ํ•˜๊ธฐ ์œ„ํ•ด ์ฝ˜์†”๋กœ ๋ฉ”์‹œ์ง€๋ฅผ ๋„์šฐ๊ณ  ์žˆ๋‹ค. ์œ„์˜ ์ด๋ฒคํŠธ ์ „ํŒŒ ๋‹จ๊ณ„์—์„œ ์งง๊ฒŒ ์–ธ๊ธ‰ํ–ˆ๋˜ Event.eventPhase๋ฅผ ์ด์šฉํ•ด ํ˜„์žฌ ํด๋ฆญ๋œ ์š”์†Œ์˜ ์ด๋ฒคํŠธ ์ „ํŒŒ ๋‹จ๊ณ„๋ฅผ ์ถœ๋ ฅํ•œ๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ์˜ Capturing ๋‹จ๊ณ„์™€ Target ๋‹จ๊ณ„

CodeSandBox์—์„œ ์ฝ”๋“œ๋ฅผ ๋ผ์ด๋ธŒ๋กœ ์ฒดํ—˜ํ•ด๋ณด๊ธฐ ๐Ÿ”

์ด ์ƒํƒœ์—์„œ ๋จผ์ € ๊ฐ€์žฅ ์ƒ์œ„ ๋ถ€๋ชจ ์š”์†Œ์ธ .redBox๋ฅผ ํด๋ฆญํ•ด๋ณด์ž.

Red box ํด๋ฆญ

.redBox๋ฅผ ํด๋ฆญํ•˜๋‹ˆ .redBox์˜ ๋ฐฐ๊ฒฝ์ƒ‰์ด ๋นจ๊ฐ„์ƒ‰์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.

์œ„์˜ ์ด๋ฒคํŠธ ํƒ€๊นƒ ์ผ๋Ÿฌ์ŠคํŠธ๋ฅผ ๋– ์˜ฌ๋ฆฌ๋ฉฐ, ์ด๋ฒคํŠธ ์ „ํŒŒ ๋‹จ๊ณ„๋ฅผ ๋‹ค์‹œ ํ•œ ๋ฒˆ ์‚ดํŽด๋ณด์ž.

.redBox๋ฅผ ํด๋ฆญํ–ˆ๊ธฐ ๋•Œ๋ฌธ์—, .redBox๊ฐ€ ์ด๋ฒคํŠธ ํƒ€๊นƒ์ด ๋˜์—ˆ๋‹ค. ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ•œ ํ›„, ์ตœ์ƒ์œ„ ์š”์†Œ์ธ window์— ํด๋ฆญ ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ๋˜์—ˆ๋‹ค. ํด๋ฆญ ์ด๋ฒคํŠธ ๊ฐ์ฒด๋Š” window์—์„œ ์‹œ์ž‘ํ•ด์„œ html, body ๋“ฑ์„ ๊ฑฐ์ณ, ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋œ ์ด๋ฒคํŠธ ํƒ€๊นƒ๊นŒ์ง€ ํ•˜์œ„ ๋ฐฉํ–ฅ๋กœ ์ด๋™ํ•œ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ Capturing ๋‹จ๊ณ„ ์ด๋‹ค.

ํด๋ฆญ ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ์ด๋ฒคํŠธ ํƒ€๊นƒ์ธ .redBox์— ๋„๋‹ฌํ•œ๋‹ค. ์ด๊ฒƒ์ด Target ๋‹จ๊ณ„ ์ด๋‹ค.

์œ„์˜ ์ฝ˜์†”์„ ๋ณด๋ฉด, redBox์˜ ์ด๋ฒคํŠธ ๋‹จ๊ณ„๋กœ Target์ด ์ถœ๋ ฅ๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

โš ๏ธ ์ฐธ๊ณ ๋กœ, Capturing ๋‹จ๊ณ„๋ฅผ ์บ์น˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š”, ์บ์น˜ ํ•˜๊ณ ์ž ํ•˜๋Š” ์š”์†Œ์˜ addEventListener์˜ ์„ธ ๋ฒˆ์งธ ์ธ์ž๋กœ true๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ํ•ด๋‹น ์ฝ”๋“œ์—๋Š” ์„ธ ๋ฒˆ์งธ ์ธ์ž๋กœ true๋ฅผ ์ „๋‹ฌํ•ด์ฃผ์ง€ ์•Š์•˜์œผ๋ฉฐ .redBox๋Š” ์ด๋ฒคํŠธ ํƒ€๊นƒ์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ฐ”๋กœ Target ๋‹จ๊ณ„๋งŒ ์บ์น˜๋œ ๋ชจ์Šต์ด๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ์˜ Bubbling ๋‹จ๊ณ„

์ด๋ฒˆ์—๋Š” .blueBox๋ฅผ ํด๋ฆญํ•ด๋ณด์ž. ํŒŒ๋ž€์ƒ‰ ํ…Œ๋‘๋ฆฌ๋ฅผ ํฌํ•จํ•œ ๊ทธ ๋‚ด๋ถ€ ์˜์—ญ์ด .blueBox์ด๋‹ค.

Blue Box ํด๋ฆญ

์‹ ๊ธฐํ•œ ์ผ์ด ๋ฒŒ์–ด์กŒ๋‹ค. .blueBox๋งŒ์„ ํด๋ฆญํ–ˆ์„ ๋ฟ์ธ๋ฐ, ๊ทธ ๋ถ€๋ชจ ์š”์†Œ์ธ .redBox์—๋„ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ์ง€๋˜์–ด .redBox์˜ ๋ฐฐ๊ฒฝ์ƒ‰์ด ํ•จ๊ป˜ ๋ณ€๊ฒฝ๋˜์—ˆ๋‹ค. ์™œ ์ด๋Ÿฐ ํ˜„์ƒ์ด ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ผ๊นŒ? ๊ทธ ์ด์œ ๋Š” ์ด๋ฒคํŠธ ์ „ํŒŒ์˜ Bubbling ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณค๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

ํŠน์ • ์š”์†Œ์—์„œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ, ์ตœ์ƒ์œ„ ์š”์†Œ์ธ window์—์„œ ์ƒ์„ฑ๋œ ์ด๋ฒคํŠธ ๊ฐ์ฒด๋Š” Capturing ๋‹จ๊ณ„์™€ Target ๋‹จ๊ณ„๋ฅผ ๊ฑฐ์ณ ์ด๋ฒคํŠธ ํƒ€๊นƒ์œผ๋กœ ์ด๋™ํ•˜๊ฒŒ ๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋ฒคํŠธ ํƒ€๊นƒ์— ๋„๋‹ฌํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ์ด๋ฒคํŠธ๊ฐ€ ์ข…๋ฃŒ๋˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋‹ค๐Ÿ™…๐Ÿปโ€โ™€๏ธ

๋‹ค์‹œ ํ•œ ๋ฒˆ ์œ„์—์„œ ์–ธ๊ธ‰๋œ ์ด๋ฒคํŠธ ์ „ํŒŒ์˜ 3๋‹จ๊ณ„๋ฅผ ์‚ดํŽด๋ณด์ž.

์ด๋ฒคํŠธ ๊ฐ์ฒด๋Š” ์ด๋ฒคํŠธ ํƒ€๊นƒ์— ๋„๋‹ฌํ•œ ํ›„์— ์ตœ์ƒ์œ„ ์š”์†Œ์ธ window์œผ๋กœ ์ƒ์œ„๋ฅผ ํ–ฅํ•ด ๋‹ค์‹œ ์ด๋™ํ•œ๋‹ค. ์ด๊ฒƒ์ด ๋ฐ”๋กœ ์ด๋ฒคํŠธ ์ „ํŒŒ์˜ ๋งˆ์ง€๋ง‰ ๋‹จ๊ณ„์ธ Bubbling ๋‹จ๊ณ„ ์ด๋‹ค.

์ด๋ฒˆ์—๋Š” .button์„ ํด๋ฆญํ•ด๋ณด์ž.

๋ฒ„ํŠผ ํด๋ฆญ

์—ญ์‹œ .button์˜ ๋ถ€๋ชจ์ธ .blueBox์™€ grand-parents์ธ .redBox๊นŒ์ง€ ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ์ง€๋˜์—ˆ๋‹ค. ์ฝ˜์†”์„ ์‚ดํŽด๋ณด๋ฉด, .button โ†’ .blueBox โ†’ .redBox ์ˆœ์œผ๋กœ ์ด๋ฒคํŠธ๊ฐ€ ๊ฐ์ง€๋œ ๊ฒƒ์„ ์•Œ ์ˆ˜ ์žˆ๋‹ค.

โš ๏ธ ํ˜„์žฌ ์ฝ˜์†”์— Capturing ๋‹จ๊ณ„๋Š” ์ถœ๋ ฅ๋˜์ง€ ์•Š์•˜๋Š”๋ฐ, ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฐ”์™€ ๊ฐ™์ด Capturing ๋‹จ๊ณ„๋ฅผ ์บ์น˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” addEventListener์˜ ์„ธ ๋ฒˆ์งธ ์ธ์ž์— true๋ฅผ ์ „๋‹ฌํ•ด์ค˜์•ผ ํ•œ๋‹ค. ํ˜„์žฌ์˜ ์ฝ”๋“œ๋Š” Bubbling ๋‹จ๊ณ„๋ฅผ ๊ด€์ฐฐํ•˜๊ธฐ ์œ„ํ•ด, ์„ธ ๋ฒˆ์งธ ์ธ์ž์— true๋ฅผ ์ „๋‹ฌํ•˜์ง€ ์•Š์€ ์ƒํƒœ์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. CodeSandBox์—์„œ ์„ธ ๋ฒˆ์งธ ์ธ์ž์— true๋ฅผ ์ „๋‹ฌํ•˜์—ฌ ์‹คํ—˜ํ•ด๋ณด์ž!

(.redBox์™€ .blueBox์˜ Capturing ๋‹จ๊ณ„์˜ ์บ์น˜๊ฐ€ ์ƒ๋žต๋˜์—ˆ๊ณ ) ์ด๋ฒคํŠธ ํƒ€๊นƒ์ธ .button์— ํด๋ฆญ ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ๋„๋‹ฌํ•˜์—ฌ .button์—์„œ Target ๋‹จ๊ณ„๊ฐ€ ๊ด€์ฐฐ๋˜์—ˆ๋‹ค.

๊ทธ๋ฆฌ๊ณ , ์ตœ์ƒ์œ„ ์š”์†Œ์ธ window๋ฅผ ํ–ฅํ•ด DOM ํŠธ๋ฆฌ์˜ ์—ญ์ˆœ์œผ๋กœ ํด๋ฆญ ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ๋‹ค์‹œ ์ด๋™ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ .button์˜ ๋ถ€๋ชจ์ธ .blueBox์— ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ๋‹ค์‹œ ์ „๋‹ฌ๋˜์–ด ๋ฐฐ๊ฒฝ์ƒ‰์ด ๋ณ€๊ฒฝ๋˜๋ฉด์„œ Bubbling ๋‹จ๊ณ„๊ฐ€ ๊ด€์ฐฐ๋˜์—ˆ๋‹ค.

๋งˆ์ฐฌ๊ฐ€์ง€๋กœ .blueBox์˜ ๋ถ€๋ชจ์ธ .redBox์— ์ด๋ฒคํŠธ ๊ฐ์ฒด๊ฐ€ ๋‹ค์‹œ ์ „๋‹ฌ๋˜์–ด ๋ฐฐ๊ฒฝ์ƒ‰์ด ๋ณ€๊ฒฝ๋˜๋ฉด์„œ Bubbling ๋‹จ๊ณ„๊ฐ€ ๊ด€์ฐฐ๋˜์—ˆ๋‹ค.

์ด์ฒ˜๋Ÿผ, ์ด๋ฒคํŠธ๋Š” ์ด๋ฒคํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚จ ์ด๋ฒคํŠธ ํƒ€๊นƒ์€ ๋ฌผ๋ก , ์ƒ์œ„ DOM ์š”์†Œ์—์„œ๋„ ์ด๋ฒคํŠธ๋ฅผ ์บ์น˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ ๋ฉˆ์ถฐ!

์ž์‹ ์š”์†Œ๋ฅผ ํด๋ฆญํ–ˆ์Œ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  Bubbling์œผ๋กœ ์ธํ•ด, ๋ถ€๋ชจ ์š”์†Œ์—๊นŒ์ง€ ์ด๋ฒคํŠธ๊ฐ€ ์ „ํŒŒ๋˜์–ด์„œ ์‹ ๊ฒฝ์ด ์“ฐ์ผ ๋•Œ. ์ด๋ฒคํŠธ ํƒ€๊นƒ์—๋งŒ ์ง‘์ค‘ํ•˜๊ณ  ์‹ถ์„ ๋•Œ.

์ด๋Ÿฐ ์ƒํ™ฉ์—๋Š” event.stopPropagation() ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋œ๋‹ค.

์ž์‹ ์š”์†Œ๋“ค์ธ .blueBox์™€ .button์„ ํด๋ฆญํ–ˆ์„ ๋•Œ๋Š” ํ•ด๋‹น ์š”์†Œ์˜ ๋ฐฐ๊ฒฝ์ƒ‰๋งŒ ๋ณ€๊ฒฝ๋˜๋„๋ก event.stopPropagation()์„ ์‚ฌ์šฉํ•ด๋ณด์ž.

const redBox = document.querySelector(".redBox");
const blueBox = document.querySelector(".blueBox");
const button = document.querySelector(".button");
const phases = ["Capturing", "Target", "Bubbling"];

function handleRedBox(event) {
  console.log("Red Box Clicked");
  console.log("Red Box ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "red";
}

function handleBlueBox(event) {
  event.stopPropagation(); // ์ถ”๊ฐ€
  console.log("Blue Box Clicked");
  console.log("Blue Box ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "blue";
}

function handlebutton(event) {
  event.stopPropagation(); // ์ถ”๊ฐ€
  console.log("Btn Clicked!");
  console.log("Button ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "black";
  this.style.color = "white";
}

redBox.addEventListener("click", handleRedBox);
blueBox.addEventListener("click", handleBlueBox);
button.addEventListener("click", handlebutton);

stopPropagation()

event.stopPropagation() ๋ฉ”์†Œ๋“œ๋ช… ๊ทธ๋Œ€๋กœ, ์ด๋ฒคํŠธ ์ „ํŒŒ๊ฐ€ ๋ฉˆ์ถ”๊ฒŒ ๋˜์–ด Bubbling์ด ๋ฐœ์ƒ๋˜์ง€ ์•Š์•˜๋‹ค.

event.target๊ณผ event.currentTarget์˜ ์ฐจ์ด

์„œ๋ก ์—์„œ ๋“ฑ์žฅํ–ˆ์—ˆ๋˜ event.target๊ณผ event.currentTarget์˜ ์ฐจ์ด์— ๋Œ€ํ•ด ์ •๋ฆฌํ•˜๊ณ ์ž ํ•œ๋‹ค.

์ด ๋ถ€๋ถ„์€ ์ง์ ‘ ๋™์ž‘ํ•ด๋ณด๋Š” ๊ฒƒ์ด ์ดํ•ด๊ฐ€ ๊ฐ€์žฅ ๋น ๋ฅด๋‹ค. ๋ฐ”๋กœ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค.

CodeSandBox์—์„œ ์ฝ”๋“œ๋ฅผ ๋ผ์ด๋ธŒ๋กœ ์ฒดํ—˜ํ•ด๋ณด๊ธฐ ๐Ÿ”

<div class="redBox">
  <button class="button">Button</button>
</div>
.redBox {
  display: flex;
  justify-content: center;
  align-items: center;
  width: 150px;
  height: 150px;
  border: 3px solid red;
  background-color: white;
}

.btn {
  border: 2px solid black;
  border-radius: 5px;
}
const redBox = document.querySelector(".redBox");
const phases = ["Capturing", "Target", "Bubbling"];

function handleRedBox(event) {
  console.log("Red Box Clicked");
  console.log("event.target: ", event.target);
  console.log("event.currentTarget: ", event.currentTarget);
  console.log("Red Box ์ด๋ฒคํŠธ ๋‹จ๊ณ„:", phases[event.eventPhase - 1]);
  this.style.backgroundColor = "red";
}

redBox.addEventListener("click", handleRedBox);

๋ถ€๋ชจ ์š”์†Œ์ธ .redBox๋Š” ์ž์‹ ์š”์†Œ์ธ .button์„ ๊ฐ€์ง€๊ณ  ์žˆ๋‹ค. .redBox์—๋งŒ ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ์„ค์ •ํ•ด๋‘” ์ƒํƒœ์ด๋ฉฐ, ์ฝ˜์†”๋กœ event.target๊ณผ event.currentTarget์ด ์–ด๋Š ๊ฒƒ์„ ๊ฐ€๋ฆฌํ‚ค๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.

์˜ˆ์ œ CodeSandBox์—์„œ ์ค‘์•™์˜ ๋ฒ„ํŠผ์„ ํด๋ฆญํ•ด๋ณด์ž.

event.target๊ณผ event.currentTarget

.redBox์— ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ํ• ๋‹น๋œ ์ƒํƒœ๋กœ .button์„ ํด๋ฆญํ•œ ๊ฒฐ๊ณผ์ด๋‹ค.

  • event.target: .button
  • event.currentTarget: .redBox

์ฆ‰, event.target์€ ์‹ค์ œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋œ ์š”์†Œ๋ฅผ, event.currentTarget์€ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๊ฐ€ ์‹ค์ œ๋กœ ํ• ๋‹น๋œ ์š”์†Œ๋ฅผ ๊ฐ€๋ฆฌํ‚จ๋‹ค.

property ์„ค๋ช…
event.currentTarget Event handler๊ฐ€ ๋“ฑ๋ก๋œ ์š”์†Œ
event.target ์‹ค์ œ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋œ ์š”์†Œ

์ด๋ฒคํŠธ ์œ„์ž„ (Event delegation)

์ด๋ฒคํŠธ ์œ„์ž„ ์ ์šฉ ์ „

์ด๋ฒคํŠธ ์ „ํŒŒ์˜ ์„ฑ์งˆ์„ ์ด์šฉํ•˜์—ฌ ์ด๋ฒคํŠธ ์œ„์ž„์„ ์ ์šฉํ•˜๋ฉด, ์ด๋ฒคํŠธ๋ฅผ ๋ณด๋‹ค ๋” ๊ฒฝ์ œ์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ด๋ฒคํŠธ ์œ„์ž„ (Event delegation) ์ด๋ž€, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ•˜์œ„ DOM ์š”์†Œ์— ๊ฐ๊ฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋Œ€์‹ , ๊ทธ ๋ถ€๋ชจ DOM์— ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค.

๊ทธ์ „์— ๋จผ์ €, ์ด๋ฒคํŠธ ์œ„์ž„์„ ์ ์šฉํ•˜๊ธฐ ์ „์˜ ์ฝ”๋“œ๋ฅผ ์‚ดํŽด๋ณด์ž. ๋ถ€๋ชจ ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋‚ด๋ถ€์˜ ๋ชจ๋“  ์ž์‹ ๋ฒ„ํŠผ ์š”์†Œ์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ์ƒํ™ฉ์ด๋‹ค.

<nav class="nav">
  <button class="button">Button 1</button>
  <button class="button">Button 2</button>
  <button class="button">Button 3</button>
</nav>
const buttons = document.querySelectorAll(".button");

function handleButtons(event) {
  console.log("Button Clicked");
}

buttons.forEach(button => button.addEventListener("click", handleButtons));

๋™์ผํ•œ ํด๋ž˜์Šค๋ช…์˜ .button์„ querySelectorAll๋กœ ํ•œ๋ฒˆ์— ์ทจ๋“ํ•˜๊ณ , ๊ฐ๊ฐ์˜ ๋ชจ๋“  .button์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ•˜๊ธฐ ์œ„ํ•ด forEach๋ฌธ์„ ์‚ฌ์šฉํ–ˆ๋‹ค.

์ด๋ฒคํŠธ ์œ„์ž„ ์ ์šฉ ์ „

๋ชจ๋“  ์ž์‹ ์š”์†Œ์— ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์œ„์™€ ๊ฐ™์€ ๋ฐฉ์‹์ด๋ผ๋ฉด ๋งŒ์•ฝ ๋‚ด๋น„๊ฒŒ์ด์…˜์˜ ์•„์ดํ…œ์ด 100๊ฐœ๋ผ๋ฉด 100๊ฐœ์˜ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•ด์•ผ ํ•  ๊ฒƒ์ด๋‹ค. DOM ์š”์†Œ์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋งŽ์ด ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด, ๋ฉ”๋ชจ๋ฆฌ ์ ์œ ์œจ์ด ๋Š˜์–ด๋‚˜๊ฒŒ ๋˜์–ด ํŽ˜์ด์ง€ ์„ฑ๋Šฅ ์ €ํ•˜์˜ ์›์ธ์ด ๋œ๋‹ค.

๋˜ํ•œ, ๋‚ด๋น„๊ฒŒ์ด์…˜ ๋‚ด๋ถ€์— ๋™์ (createElement ๋“ฑ)์œผ๋กœ ์ถ”ํ›„์— ๋˜๋‹ค๋ฅธ .button ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋˜๋Š” ๊ฒฝ์šฐ๋ฅผ ์ƒ๊ฐํ•ด๋ณด์ž. .button์— ํด๋ฆญ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ–ˆ๋˜ ์‹œ์ ์— .button์€ ๋‘ ๊ฐœ์˜€๋‹ค. ๋”ฐ๋ผ์„œ ์ถ”๊ฐ€๋œ ์š”์†Œ์—๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ๋“ฑ๋ก๋˜์ง€ ์•Š์•˜๋‹ค. ์ถ”๊ฐ€๋˜๋Š” ์š”์†Œ์—๋Š” ๋งค๋ฒˆ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•ด์ฃผ์ง€ ์•Š๋Š” ์ด์ƒ, ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ๋™ํ•˜์ง€ ์•Š๊ฒŒ ๋œ๋‹ค. ์ฆ‰, ์œ ์ง€ ๋ณด์ˆ˜ํ•˜๊ธฐ ์–ด๋ ค์šด ์ฝ”๋“œ๋ฅผ ์ƒ์‚ฐํ•˜๊ฒŒ ๋œ๋‹ค.

์ด๋ ‡๊ฒŒ ๋ชจ๋“  ์ž์‹ ์š”์†Œ์— ์ผ์ผ์ด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•ด์ฃผ๋Š” ๊ฒƒ์€ ๊ฒฐ์ฝ” ์ข‹์€ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋ฐ”๋กœ ์ด๋ฒคํŠธ ์œ„์ž„์ด๋‹ค.

์ด๋ฒคํŠธ ์œ„์ž„ ์ ์šฉ ํ›„

์ด๋ฒคํŠธ ์œ„์ž„ (Event delegation) ์ด๋ž€, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ•˜์œ„ DOM ์š”์†Œ์— ๊ฐ๊ฐ ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋Œ€์‹ , ๊ทธ ๋ถ€๋ชจ DOM์— ์ด๋ฒคํŠธ ํ•ธ๋“ค๋Ÿฌ๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ์‹์„ ๋งํ•œ๋‹ค.

์ด๋ฒคํŠธ ์ „ํŒŒ์—์„œ ์‚ดํŽด๋ณธ ๋ฐ”์™€ ๊ฐ™์ด, ์ด๋ฒคํŠธ๋Š” ์ด๋ฒคํŠธ ํƒ€๊นƒ์€ ๋ฌผ๋ก  ๊ทธ ์ƒ์œ„ DOM ์š”์†Œ์—์„œ๋„ ์บ์น˜ํ•œ๋‹ค, Bubbling ๋‹จ๊ณ„๊ฐ€ ์กด์žฌํ•œ๋‹ค๋Š” ์ ์„ ๋– ์˜ฌ๋ฆฌ์ž.

๋”ฐ๋ผ์„œ ์ƒ์œ„ DOM ์š”์†Œ์— ์ด๋ฒคํŠธ ๋“ฑ๋ก์„ ์œ„์ž„ํ•˜๋ฉด, ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํ•˜์œ„ DOM ์š”์†Œ์— ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค. ๋˜ํ•œ ๋™์ ์œผ๋กœ ํ•˜์œ„ DOM ์š”์†Œ๊ฐ€ ์ถ”๊ฐ€๋˜๋”๋ผ๋„, ์ถ”๊ฐ€๋œ DOM ์š”์†Œ์— ์ผ์ผ์ด ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๋ฅผ ๋“ฑ๋กํ•˜์ง€ ์•Š์•„๋„ ๋œ๋‹ค.

์œ„์˜ ์ฝ”๋“œ๋ฅผ ์ด๋ฒคํŠธ ์œ„์ž„์„ ์‘์šฉํ•˜์—ฌ ์•„๋ž˜์™€ ๊ฐ™์ด ์ˆ˜์ •ํ•ด๋ณด์•˜๋‹ค.

<nav class="nav">
  <button class="button" data-number="1">Button 1</button>
  <button class="button" data-number="2">Button 2</button>
  <button class="button" data-number="3">Button 3</button>
</nav>
.nav {
  display: flex;
  justify-content: center;
  align-items: center;
  padding: 10px;
  background-color: green;
}
const nav = document.querySelector(".nav");

function handleClick(event) {
  console.log("Clicked");
  console.log(event.target.dataset.number);
}

nav.addEventListener("click", handleClick);

์ดˆ๋ก์ƒ‰ ์˜์—ญ์˜ ๋ถ€๋ชจ ์š”์†Œ์ธ .nav์— ํด๋ฆญ ์ด๋ฒคํŠธ๋ฅผ ๋“ฑ๋กํ–ˆ๊ณ , ์–ด๋–ค ๋ฒ„ํŠผ์ด ํด๋ฆญ๋˜์—ˆ๋Š”์ง€ ํŒ๋ณ„ํ•˜๊ธฐ ์œ„ํ•ด .button์— ๊ฐ๊ฐ data ์†์„ฑ์„ ์ถ”๊ฐ€ํ•ด์ฃผ์—ˆ๋‹ค. ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋˜๋ฉด data-number์˜ ๊ฐ’์ด ํ•จ๊ป˜ ์ถœ๋ ฅ๋œ๋‹ค.

์ด๋ฒคํŠธ ์œ„์ž„

๋ถ€๋ชจ ์š”์†Œ์ธ .nav์— ์ด๋ฒคํŠธ๋ฅผ ์œ„์ž„ํ•˜์—ฌ ๋“ฑ๋กํ–ˆ์Œ์—๋„, ์ด๋ฒคํŠธ ๋ฒ„๋ธ”๋ง์œผ๋กœ ์ธํ•ด ์ž์‹ ์š”์†Œ์ธ .button์—๋„ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ์ ์šฉ๋˜์—ˆ๋‹ค. .button์˜ data-number์˜ ๊ฐ’๋„ ์ •ํ™•ํžˆ ํ”„๋ฆฐํŠธ๊ฐ€ ๋˜๊ณ  ์žˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์ด๋ฒคํŠธ๊ฐ€ ๋“ฑ๋ก๋œ ๋‹น์‚ฌ์ž์ด์ž, ๋ถ€๋ชจ ์š”์†Œ์ธ .nav๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ๋„ ๋‹น์—ฐํ•˜๊ฒŒ๋„ ํด๋ฆญ ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋œ๋‹ค. ๋ฌธ์ œ๋Š” .nav์—๋Š” data ์†์„ฑ์„ ์ง€์ •ํ•ด์ฃผ์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์—, data-number์˜ ๊ฐ’์ด undefined๋กœ ์ถœ๋ ฅ๋œ๋‹ค๋Š” ์ ์ด๋‹ค.

์—ฌ๊ธฐ์„œ ๋“œ๋Ÿฌ๋‚˜๋Š” ์ด๋ฒคํŠธ ์œ„์ž„์˜ ๋‹จ์ ์€, ์ด๋ฒคํŠธ๊ฐ€ ๋ฐœ์ƒ๋œ DOM ์š”์†Œ๊ฐ€ ๊ฐœ๋ฐœ์ž๊ฐ€ ๊ธฐ๋Œ€ํ•œ DOM ์š”์†Œ๊ฐ€ ์•„๋‹ ์ˆ˜๋„ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค. ๋”ฐ๋ผ์„œ ์ด๋ฒคํŠธ์— ๋ฐ˜์‘์ด ํ•„์š”ํ•œ DOM ์š”์†Œ(์œ„์˜ ์˜ˆ์‹œ์˜ ๊ฒฝ์šฐ .button)์— ํ•œ์ •ํ•˜์—ฌ ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ์‹คํ–‰๋˜๋„๋ก ์ด๋ฒคํŠธ ํƒ€๊นƒ์„ ๊ฒ€์‚ฌํ•  ํ•„์š”๊ฐ€ ์žˆ๋‹ค.

JavaScript ์ฝ”๋“œ๋ฅผ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ˆ˜์ •ํ•ด๋ณด์•˜๋‹ค.

const nav = document.querySelector(".nav");

function handleClick(event) {
  const { target } = event;

  // event.target์ด .nav์˜ ์ž์‹ ์š”์†Œ์ธ .button์ด ์•„๋‹ˆ๋ผ๋ฉด ํ•จ์ˆ˜ ์ข…๋ฃŒ
  if (!target.matches(".nav > .button")) return;

  console.log("Clicked");
  console.log(target.dataset.number);
}

nav.addEventListener("click", handleClick);

ํ•ด๋‹น ์š”์†Œ๊ฐ€ ๊ฒ€์‚ฌํ•˜๊ณ ์ž ํ•˜๋Š” selector๊ฐ€ ๋งž๋Š”์ง€ ์ฒดํฌํ•  ์ˆ˜ ์žˆ๋Š” Element.matches() ๋ฉ”์†Œ๋“œ๋ฅผ ์ด์šฉํ–ˆ๋‹ค.

event.target์ด .nav์˜ ์ž์‹ ์š”์†Œ์ธ .button์ด ์•„๋‹ˆ๋ผ๋ฉด ํ•จ์ˆ˜ ์ข…๋ฃŒ์‹œํ‚จ๋‹ค.

CodeSandBox ์ƒ˜ํ”Œ ์ฝ”๋“œ ๐Ÿ”

์ด๋ฒคํŠธ ์œ„์ž„ ์ด๋ฒคํŠธ ํƒ€๊นƒ ์ฒดํฌ ์ถ”๊ฐ€

.button์„ ํด๋ฆญํ–ˆ์„ ๋•Œ์—๋งŒ ์ด๋ฒคํŠธ๊ฐ€ ๋™์ž‘ํ•˜๊ณ , .nav๋ฅผ ํด๋ฆญํ–ˆ์„ ๋•Œ๋Š” ์ด๋ฒคํŠธ๊ฐ€ ๋™์ž‘ํ•˜์ง€ ์•Š๊ฒŒ ๋˜์—ˆ๋‹ค!

๋งˆ์น˜๋ฉฐ

event.target, event.currentTarget์œผ๋กœ ์‹œ์ž‘ํ•œ ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ๊ถ๊ธˆ์ฆ์ด, ์ด๋ฒคํŠธ ์ „ํŒŒ์™€ ์ด๋ฒคํŠธ ์œ„์ž„๊นŒ์ง€ ๋ฐœ์ „๋˜์—ˆ๋‹ค. ์ƒ๊ฐ ์™ธ๋กœ ์†Œ์†Œํ•˜์ง€๋งŒ ๋งŽ์€ ๋‚ด์šฉ์„ ๋‹ด๊ฒŒ ๋˜์–ด ํฌ์ŠคํŒ…์ด ๊ฝค๋‚˜ ๊ธธ์–ด์ง„ ๊ฒƒ ๊ฐ™๋‹ค. ์ด๋ฒคํŠธ์— ๋Œ€ํ•œ ํฐ ๊ทธ๋ฆผ, ํšจ์œจ์ ์ธ ์ด๋ฒคํŠธ ๋ฐ”์ธ๋”ฉ์„ ํ•™์Šตํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ ์ข‹์€ ์‹œ๊ฐ„์ด์—ˆ๋‹ค.

๋ถ€์กฑํ•œ ๋‚ด์šฉ, ์ž˜๋ชป๋œ ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋ฉด ์ฝ”๋ฉ˜ํŠธ๋กœ ์ง€์  ๋ถ€ํƒ๋“œ๋ฆฝ๋‹ˆ๋‹ค.

Reference

Profile picture

Written by iamhayoung who write and build stuff on internet ๐ŸŒ
GitHub