์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ์ด๋ฒคํธ์ ๋ํ ๋ค์ํ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๋ event
๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ , ์์ฑ๋ event
๊ฐ์ฒด๋ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ฌ๋๋ค. event
๊ฐ์ฒด ๋ด๋ถ์๋ ๋ค์ํ ํ๋กํผํฐ๋ค์ด ์กด์ฌํ์ง๋ง, ๊ทธ ์ค ๋จ์ฐ ์์ฃผ ์ฌ์ฉํ๋ ํ๋กํผํฐ๋ฅผ ๋งํด๋ณด์๋ฉด event.target
์ด ์๋๊น ์ถ๋ค.
์ฐ์ฐํ event.target
๊ณผ event.currentTarget
์ ์ฐจ์ด์ ๋ํด ์กฐ์ฌ๋ฅผ ํ๊ฒ ๋์๋๋ฐ, ์ด ๊ณผ์ ์์ ์ด๋ฒคํธ๊ฐ ์ด๋ค ๋ฐฉ์์ผ๋ก ์ด๋ฒคํธ ํ๊น์ ์ ๋ฌ๋๋์ง์ ๋ํ ์ดํด๊ฐ ๋ถ์กฑํ๋ค๋ ๊ฒ์ ๊นจ๋ฌ์๋ค.
์ด๋ฒ ๊ธฐํ์ JavaScript์ ์ด๋ฒคํธ ์ ํ, ์ด๋ฒคํธ ์บก์ณ๋ง, ์ด๋ฒคํธ ๋ฒ๋ธ๋ง, ๊ทธ๋ฆฌ๊ณ ์ด๋ฒคํธ ์์์ ๋ํด ์กฐ์ฌํด๋ณด์๊ณ , ๊ทธ ๋ด์ฉ์ ๋ํด ์ ๋ฆฌํด๋ณธ๋ค.
DOM (Document Object Model)
<!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๋จ๊ณ๋ก ๋๋๋ค.
- ์บก์ณ๋ง ๋จ๊ณ (Capturing Phase): ์ด๋ฒคํธ๊ฐ ์์ ์์ โ ํ์ ์์ ๋ฐฉํฅ์ผ๋ก ์ ํ
- ํ๊น ๋จ๊ณ (Target Phase): ์ด๋ฒคํธ๊ฐ ์ด๋ฒคํธ ํ๊น์ ๋๋ฌ
- ๋ฒ๋ธ๋ง ๋จ๊ณ (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;
}
๊ฐ๊ฐ์ ์์์๋ ์์ญ์ ๋ช ํํ ํ์ํ๊ณ ์, 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
๋ฅผ ํด๋ฆญํด๋ณด์.
.redBox
๋ฅผ ํด๋ฆญํ๋ .redBox
์ ๋ฐฐ๊ฒฝ์์ด ๋นจ๊ฐ์์ผ๋ก ๋ฐ๋์๋ค.
์์ ์ด๋ฒคํธ ํ๊น ์ผ๋ฌ์คํธ๋ฅผ ๋ ์ฌ๋ฆฌ๋ฉฐ, ์ด๋ฒคํธ ์ ํ ๋จ๊ณ๋ฅผ ๋ค์ ํ ๋ฒ ์ดํด๋ณด์.
.redBox
๋ฅผ ํด๋ฆญํ๊ธฐ ๋๋ฌธ์, .redBox
๊ฐ ์ด๋ฒคํธ ํ๊น์ด ๋์๋ค. ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ํ, ์ต์์ ์์์ธ window
์ ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ฒด๊ฐ ์์ฑ๋์๋ค. ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ฒด๋ window
์์ ์์ํด์ html
, body
๋ฑ์ ๊ฑฐ์ณ, ์ด๋ฒคํธ๊ฐ ๋ฐ์๋ ์ด๋ฒคํธ ํ๊น๊น์ง ํ์ ๋ฐฉํฅ๋ก ์ด๋ํ๋ค. ์ด๊ฒ์ด ๋ฐ๋ก Capturing ๋จ๊ณ
์ด๋ค.
ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ฒด๊ฐ ์ด๋ฒคํธ ํ๊น์ธ .redBox
์ ๋๋ฌํ๋ค. ์ด๊ฒ์ด Target ๋จ๊ณ
์ด๋ค.
์์ ์ฝ์์ ๋ณด๋ฉด, redBox
์ ์ด๋ฒคํธ ๋จ๊ณ๋ก Target
์ด ์ถ๋ ฅ๋ ๊ฒ์ ์ ์ ์๋ค.
โ ๏ธ ์ฐธ๊ณ ๋ก, Capturing ๋จ๊ณ๋ฅผ ์บ์นํ๊ธฐ ์ํด์๋, ์บ์น ํ๊ณ ์ ํ๋ ์์์
addEventListener
์ ์ธ ๋ฒ์งธ ์ธ์๋กtrue
๋ฅผ ์ ๋ฌํด์ฃผ์ด์ผ ํ๋ค. ํด๋น ์ฝ๋์๋ ์ธ ๋ฒ์งธ ์ธ์๋กtrue
๋ฅผ ์ ๋ฌํด์ฃผ์ง ์์์ผ๋ฉฐ.redBox
๋ ์ด๋ฒคํธ ํ๊น์ด๊ธฐ ๋๋ฌธ์, ๋ฐ๋ก Target ๋จ๊ณ๋ง ์บ์น๋ ๋ชจ์ต์ด๋ค.
์ด๋ฒคํธ ์ ํ์ Bubbling ๋จ๊ณ
์ด๋ฒ์๋ .blueBox
๋ฅผ ํด๋ฆญํด๋ณด์. ํ๋์ ํ
๋๋ฆฌ๋ฅผ ํฌํจํ ๊ทธ ๋ด๋ถ ์์ญ์ด .blueBox
์ด๋ค.
์ ๊ธฐํ ์ผ์ด ๋ฒ์ด์ก๋ค. .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);
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์์ ์ค์์ ๋ฒํผ์ ํด๋ฆญํด๋ณด์.
.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
- ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ Deep Dive, ์ด์ ๋ชจ ์
- MDN | Event properties
- JavaScript ใฎใคใใณใไผๆญใฃใฆ๏ผ๏ผaddEventListener ใฎ็ฌฌไธๅผๆฐใซใคใใฆใ๏ผ
- ์ํ์ฝ๋ฉ | JavaScript - ์ด๋ฒคํธ์ ํ (2/3) : ์บก์ฒ๋ง
- ์ํ์ฝ๋ฉ | JavaScript - ์ด๋ฒคํธ์ ํ (3/3) : ๋ฒ๋ธ๋ง
- MDN | Comparison of Event Targets
- MDN | Element.matches()