์ด๋ฒคํธ๋ ์์คํ ์์ ์ผ์ด๋๋ ์ฌ๊ฑด ํน์ ๋ฐ์์ด๋ค. ์์คํ ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ ๋ '์ ํธ'๋ฅผ ๋ณด๋ด๊ณ ์ํ๋ค๋ฉด ์ด๋ฒคํธ์ ์ด๋ ํ ๋ฐฉ์์ผ๋ก ์๋ต๋ ํ ์ ์๋ค...!
์น ๋ธ๋ผ์ฐ์ ์์๋ ์ด๋ฒคํธ๊ฐ ๋ธ๋ผ์ฐ์ ์ ์๋์ฐ ๋ด์์ ๋ฐ์ํ๋ค.
=> ์ฌํ ์ฌ์ฉํ๋ ๊ฒ์ฒ๋ผ ํน์ ์์์ ๋ถ์ฐฉ๋๋ ๊ฒฝํฅ์ด ์๋ค.
์น์์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๊ฐ๋ฐ์๋ ๊ทธ ์ด๋ฒคํธ์ ๋์ํ๋ ํธ๋ค๋ฌ๋ฅผ ์ค์ ํ ์ ์๋ค.
ํฌ๊ฒ ๋ ๊ณผ์ ์ผ๋ก ๋๋ ์ ์๋๋ฐ, ์ฒซ ๋ฒ์งธ๋ก ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ฅผ ๋ฑ๋กํ๊ณ ๋ ๋ฒ์งธ๋ก ๊ทธ ์ด๋ฒคํธ์ ์๋ตํ๋ ํธ๋ค๋ฌ๋ฅผ ์ค์ ํ๋ ๊ฒ์ด๋ค.
์ฆ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ค๋ ๊ฒ์ ํน์ ์ด๋ฒคํธ ๋ฐ์์ ์๋ต์ผ๋ก ์คํ๋๋ ์ฝ๋ ๋ธ๋ก์ ์ง์ ํ๋ ๊ณผ์ ์ด๋ค.
์ด๋ฒคํธ๋ฅผ ๋ฑ๋กํ๋ ๊ฒ์ ๋ํ์ ์ผ๋ก ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ด ์๋ค.
<button class="button" onclick="handleClick()">๋๋ฌ์ฃผ์ธ์!</button>
document.querySelector('.button').addEventListener('click', handleClick);
๊ณต์ ๋ฌธ์์์๋ ์ฒซ ๋ฒ์งธ ๋ฐฉ๋ฒ์ฒ๋ผ ์ธ๋ผ์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๊ธฐ ๋ณด๋ค๋ js ํ์ผ์์ addEventListener ๋ฉ์๋๋ฅผ ํ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๊ณ ์๋ค.
์ธ๋ผ์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํ๋์ ๋ฉ์๋๋ง ๋ฑ๋กํ ์ ์๊ณ , HTML ํ์ผ ๋ด์ ์คํฌ๋ฆฝํธ๊ฐ ๋ค์ด์์ผ๋ฉด ๊ตฌ๋ฌธ ๋ถ์์ด ์ด๋ ค์์ง๊ธฐ ๋๋ฌธ์ด๋ค.
๋ด ์๊ฐํ๊ธฐ์ ๊ฐ์ฅ ์ค์ํ ์ด์ ๋ ์์คํ ์ ์์ธก ๊ฐ๋ฅํ๊ฒ ๋ง๋ค๊ธฐ ์ํจ์ธ ๊ฒ ๊ฐ๋ค. ์คํฌ๋ฆฝํธ ํ์ผ์ ์ผ๊ด์ ์ผ๋ก ์ด๋ฒคํธ๋ฅผ ์์ฑํ๋ฉด ์ ์ง๋ณด์์ ๋์์ด ๋๊ธฐ ๋๋ฌธ์ด๋ค.
document.querySelector('.button').onclick = handleClick;
๋ค์๊ณผ ๊ฐ์ด ํ๋กํผํฐ๋ก๋ ์ค์ ํ ์ ์๋๋ฐ ์ด ๊ฒฝ์ฐ๋ ํ๋์ ์ด๋ฒคํธ๋ง ๋ฑ๋ก ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ์ถ์ฒํ๋ ๋ฐฉ๋ฒ์ ์๋๋ค.
๋ชจ๋ํ ๋ฐฉ๋ฒ์ธ addEventListener, removeEventListener ๋ฉ์๋๋ฅผ ์ด์ฉํด ์ด๋ฒคํธ๋ฅผ ํ๋ถ์ฐฉํ๋ ๊ฒ ๊ถ์ฅ๋๋ค.
function handleClick(e) {
console.log(e);
}
document.querySelector(".btn").onclick = handleClick;
window.addEventListener("keyup", (e) => {
console.log(e);
});
์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ฉด ๋ธ๋ผ์ฐ์ ๋ ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ํธ๋ค๋ฌ์ ๊ทธ๊ฒ์ ์ ๋ฌํ๋ค. ์์์ ๊ฐ๊ฐ ํค๋ณด๋ ์ด๋ฒคํธ์ ๋ง์ฐ์ค ์ด๋ฒคํธ ๊ฐ์ฒด๋ฅผ console์ ์ถ๋ ฅํ ๊ฒฐ๊ณผ๋ฅผ ๋ณผ ์ ์๋ค.
์ด๋ฒคํธ ๊ฐ์ฒด์๋ ๋ค์ํ ์ ๋ณด๊ฐ ๋ด๊ฒจ์๋ค. ๋ง์ฐ์ค ์ด๋ฒคํธ ๊ฐ์ ๊ฒฝ์ฐ๋ ํ์ฌ ๋ง์ฐ์ค ํฌ์ธํฐ์ ์์น๋ถํฐ alt๋ shift ํค์ ๋๋ฆผ ์ฌ๋ถ๊น์ง ์ ์ ์๋ค.
์ด๋ฐ ์ธ์ธํ ์ ๋ณด๋ค๋ ์ํฉ์ ๋ฐ๋ผ ์ฐ์ด๊ฒ ์ง๋ง ์ฌํ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉํ๋ ๊ฑด ์ด๋ฒคํธ์ target์ ๋ํ ์ ๋ณด์ด๋ค.
์ด๋ฒคํธ ๊ฐ์ฒด์ ํ๊ฒ์ ์ค์ฌ์ผ๋ก ์ด์ผ๊ธฐํด๋ณด๊ฒ ๋ค.
target์ ์ด๋ฆ ๊ทธ๋๋ก ์ง๊ด์ ์ด๋ค. ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์๋ฅผ target์ผ๋ก ์ฐธ์กฐํ ์ ์๋ค.
<input type="number" name="numberInput" id="inputId" />
function handleClick(e) {
console.log(e.target.value);
console.log(e.target.name);
}
์ด์ฒ๋ผ input์ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ฐฉํ๋ฉด ์ฐธ์กฐ ๋์์ value๋ name ๋ํ ํ์ธํ ์ ์๋ค.
๊ทธ๋ ๋ค๋ฉด target์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋ถ์ฐฉ๋ ์์์ผ๊น?
๊ทธ๋ด ์๋ ์์ง๋ง ๊ทธ๋ ์ง ์์ ์๋ ์๋ค. ์ด ๋ง์ ์๋ฏธ๋ฅผ ์์ธํ ์ดํด๋ณด์.
์ฐ์ ์ด๋ฒคํธ์ ์คํ ๊ณผ์ ๋ถํฐ ์์๋ณด์.
<body>
<button class="btn">๋ฒํผ์ด๊ธ</button>
</body>
document
.querySelector(".btn")
.addEventListener("click", () => alert("target: btn"));
document
.querySelector("body")
.addEventListener("click", () => alert("bubbled body"));
document
.querySelector("body")
.addEventListener("click", () => alert("captured body"), { capture: true });
๋ค์๊ณผ ๊ฐ์ ์คํฌ๋ฆฝํธ๊ฐ ์์ ๋ ๋ฒํผ์ ํด๋ฆญํ๋ฉด ์ด๋ป๊ฒ ๋ ๊น?
"captured body" => "target: btn" => "bubbled body" ์์ผ๋ก alert ์ฐฝ์ด ๋ฐ์ํ๋ค.
์ฐ๋ฆฌ๋ ๋ฒํผ์ ํด๋ฆญํ์ง๋ง ์ฌ์ค์ body๋ฅผ ํด๋ฆญํ๋ค๊ณ ๋ ํ ์ ์๋ค. body ๋ด๋ถ์ ์กด์ฌํ๋ ๋ฒํผ์ด๊ธฐ ๋๋ฌธ์ body๋ฅผ ํด๋ฆญํ์ง ์๊ณ ์๋ ๋ฒํผ ํด๋ฆญ ๋ํ ๋ถ๊ฐ๋ฅํ๋ค.
์ด๋ ๊ฒ ์์์์ ํ์๋ก ์ด๋ฒคํธ๊ฐ ์ ํํ๋ ํ์์ด ์๋๋ฐ ์ด๊ฒ์ event capturing์ด๋ผ๊ณ ํ๋ค.
์ด๋ฒคํธ ํธ๋ค๋ฌ์์ ์บก์ณ๋ง์ ์ ์ฉํ๊ณ ์ถ๋ค๋ฉด 3๋ฒ์งธ ์ด๋ฒคํธ ๋ฑ๋ก์ฒ๋ผ option์ผ๋ก capture ์ค์ ์ ํ๋ฉด ๋๋ค.
์บก์ณ๋ ์ค๋ช ๊ณผ ๊ฐ์ด ์ง๊ด์ ์ด๋ค. ๋ถ๋ชจ๋ฅผ ํด๋ฆญํด์ผ ์์์ ํด๋ฆญ๋๋ ๋ง์ด๋ค.
ํ์ง๋ง "bubbled body"๋ ๋ชจํธํ๋ค. ์ด๊ฒ ๋ํ ์ด๋ฒคํธ ๋ฐ์์ ํน์ง์ธ๋ฐ ์ด๋ฒคํธ ์บก์ณ๋ง๊ณผ๋ ๋ฐ๋๋ก ์์ฉํ๋ค.
์ด๋ฒคํธ ๋ฐ์ ์์์ธ ํ๊ฒ์ผ๋ก๋ถํฐ ์ต์์ ๋ถ๋ชจ๊น์ง ๋น๋๋ฐฉ์ธ์ฒ๋ผ ์ฌ๋ผ๊ฐ๋ ํ์, ์ด๊ฒ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ด๋ค.
document.querySelector(".btn").addEventListener("click", (e) => {
console.log("target: btn");
console.log(" target: ", e.target);
console.log(" cTarget: ", e.currentTarget);
});
document.querySelector("body").addEventListener("click", (e) => {
console.log("bubbled body");
console.log(" target: ", e.target);
console.log(" cTarget: ", e.currentTarget);
});
document.querySelector("html").addEventListener("click", (e) => {
console.log("bubbled html");
console.log(" target: ", e.target);
console.log(" cTarget: ", e.currentTarget);
});
document.querySelector("body").addEventListener(
"click",
(e) => {
console.log("captured body");
console.log(" target: ", e.target);
console.log(" cTarget: ", e.currentTarget);
},
{ capture: true }
);
์ด๋ฒคํธ์ target์ ์์์ ์ค๋ช ํ๋ค. ๊ทธ๊ฒ์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์๋ก ์บก์ณ๋ง-๋ฒ๋ธ๋ง ๋จ๊ณ์์ ์ค์์ ์ธ target์ ํด๋นํ๋ค.
์ฆ ์ด๋ฒคํธ๊ฐ ๋ฑ๋ก๋ ์์๊ฐ ์๋ ์๋ ์๋ ๊ฒ์ด๋ค. ์์ ์คํฌ๋ฆฝํธ๋ฅผ ํด๋ฆญ ์ด๋ฒคํธ๋ก ์คํ์์ผ๋ณด๋ฉด ๊ทธ๊ฒ์ ํ์ธํ ์ ์๋ค.
๋ณด์ด๋ ๊ฒ์ฒ๋ผ target์ ํญ์ button์ด๋ค. ๋ง์ฝ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋ถ์ฐฉ๋ ์์๋ฅผ ์๊ณ ์ถ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์ด๋ ํ์ฉํ ์ ์๋ ๊ฒ currentTarget์ด๋ค. ์ด๊ฒ๋ console์์ ๋ณด์ด๋ ๊ฒ์ฒ๋ผ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ๋ถ์ฐฉ๋ ์์๊ฐ ๋ํ๋๋ ๊ฑธ ํ์ธํ ์ ์๋ค.
์ ๋ฆฌํ์๋ฉด event.target์ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ์์์ ๋ํ ์ฐธ์กฐ, event.currentTarget์ ์ด๋ฒคํธ๊ฐ ๋ถ์ฐฉ๋ ์์์ ๋ํ ์ฐธ์กฐ, ์ฆ ํธ๋ค๋ฌ์ this๋ผ๊ณ ๋ณผ ์ ์๋ค.
๋ฒ๋ธ๋ง, ์บก์ณ๋ง ์ฒ์ ๋ง์ฃผํ๋ฉด ๋ฒ๊ฑฐ๋กญ๊ธฐ๋ง ํ๋ค. ์ ์ด๋ฐ ๊ฑธ ๋ง๋ค์๋์ง ์๋ฌธ์ด์ง๋ง ์ด๋ฐ ํ์์ ์์ฃผ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์๋ ๊ธฐ๋ฒ์ด ์๋ค.
<ul class="container">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
<li class="item">item6</li>
<li class="item">item7</li>
<li class="item">item8</li>
<li class="item">item9</li>
<li class="item">item10</li>
</ul>
๋ค์๊ณผ ๊ฐ์ ๋ฆฌ์คํธ ์๋ฆฌ๋จผํธ๋ค์ด ์์ ๋ ๊ฐ๊ฐ์ ํด๋ฆญํ ๋ innerText๋ฅผ ์ป๊ณ ์ถ๋ค. ์ด ๊ฒฝ์ฐ ์ด๋ป๊ฒ ํด์ผํ ๊น?
์ง๊ด์ ์ผ๋ก ๋ ์ค๋ฅด๋ ๋ฐฉ๋ฒ์ ๋ค์๊ณผ ๊ฐ๋ค.
document
.querySelectorAll(".container .item")
.forEach((item) =>
item.addEventListener("click", (e) => console.log(e.target.innerText))
);
๊ทธ๋ฅ NodeList๋ฅผ ๊ตฌํ๊ณ forEach ๋ฉ์๋๋ก ๊ฐ๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์ค์ ํด์ฃผ๋ฉด ๋๋ค.
๋ง์ฝ item์ด 1๋ง๊ฐ๋ผ๋ฉด ์ด๋จ๊น? 1๋ง๊ฐ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ถ์ฐฉํด์ผํ๋ค. ๋ณ๋ก ๋งค๋ ฅ์ ์ธ ๋ฐฉ์์ด ์๋ ๊ฒ ๊ฐ๋ค.
์ด๋ฒคํธ ๋ฒ๋ธ๋ง์ ์ด์ฉํ๋ฉด ์ด๋ฐ ๋ฌธ์ ๋ฅผ ์์ฃผ ํจ์จ์ ์ผ๋ก ํด๊ฒฐํ ์ ์๋ค.
document
.querySelector(".container")
.addEventListener("click", (e) => console.log(e.target.innerText));
๋ค์๊ณผ ๊ฐ์ด ํ๋์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ก๋ ๊ฐ์ ๊ฒฐ๊ณผ๋ฅผ ๋ผ ์ ์๋ค!
์ด๋ฒคํธ๊ฐ ๋ถ๋ชจ๋ก ๊ณ์ ์ ํ๋๋ ๋ฒ๋ธ๋ง์ ํน์ฑ์ ์ด์ฉํ ์ด๋ฒคํธ ์์์ด๋ผ๋ ๊ธฐ๋ฒ์ด๋ค.
<li class="item">
item1
<div>hello?</div>
</li>
๊ฐ์ ์ฝ๋์์ li๊ฐ div๋ฅผ ํ๊ณ ์๋ ํํ๋ค.
์ฐ๋ฆฌ๊ฐ div๋ฅผ ํด๋ฆญํ์ ๋ ์๋ฌด ์ผ๋ ๋ฐ์ํ์ง ์๊ณ div๊ฐ ์๋ li ์์ญ์ ํด๋ฆญํ์ ๋๋ง ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํค๊ณ ์ถ๋ค๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น?
์๊ฐ๋ณด๋ค ๊ฐ๋จํ๋ค.
document.querySelector(".container").addEventListener("click", (e) => {
if (e.target.tagName === "DIV") {
return;
}
console.log(e.target.innerText);
});
์กฐ๊ธ ์์์ ์ด์ง๋ง target์ tagName์ ํ์ธํ๋ ๊ฒ์ผ๋ก ์ด๋ฒคํธ์ ๋ฐ์์ ๋ฐฉ์งํ ์ ์๋ค.
document.querySelector(".container").addEventListener("click", (e) => {
// if (e.target.tagName === "DIV") {
// return;
// }
console.log(e.target.closest("li").innerText);
});
ํน์ ๋ค์๊ณผ ๊ฐ์ด element์ closest ๋ฉ์๋๋ฅผ ์ด์ฉํ ์๋ ์๋ค. closest ๋ฉ์๋๋ ํธ์ถ ์๋ฆฌ๋จผํธ์์ ์ธ์๋ก ๋ฐ์ ์ ๋ ํฐ๋ฅผ ๊ฐ์ง๊ณ ์๋ ๊ฐ์ฅ ๊ฐ๊น์ด ๋ถ๋ชจ๋ฅผ ์ฐธ์กฐํ๋ค.
Element์ closest() ๋ฉ์๋๋ ์ฃผ์ด์ง CSS ์ ํ์์ ์ผ์นํ๋ ์์๋ฅผ ์ฐพ์ ๋๊น์ง, ์๊ธฐ ์์ ์ ํฌํจํด ์์ชฝ(๋ถ๋ชจ ๋ฐฉํฅ, ๋ฌธ์ ๋ฃจํธ๊น์ง)์ผ๋ก ๋ฌธ์ ํธ๋ฆฌ๋ฅผ ์ํํฉ๋๋ค.
์บก์ณ๋ง๋ ์ ๋ฆฌํ๊ธด ํ๋๋ฐ ์บก์ณ๋ง์ ์ด๋ป๊ฒ ์จ๋จน์ด์ผ ํ ์ง ๊ฐ์ด ์ ์จ๋ค... ๐
์ฐธ๊ณ ๋ก ๋ชจ๋ ์ด๋ฒคํธ๊ฐ ๋ฒ๋ธ๋ง๋๋ ๊ฑด ์๋๋ค. focus์ฒ๋ผ ๋ฒ๋ธ๋ง์ด ์ ๋๋ ์ผ์ด์ค๊ฐ ๋๋ฌผ๊ฒ ์๋ค.