์์ฑ์ : ์ด์ฌ๊ธฐ
- DOM ํธ๋ฆฌ ์์ ์กด์ฌํ๋ DOM ์์ ๋
ธ๋์์ ๋ฐ์ํ ์ด๋ฒคํธ๋ DOM ํธ๋ฆฌ๋ฅผ ํตํด ์ ํ๋๋ค. ์ด๋ฅผ ์ด๋ฒคํธ ์ ํ๋ผ ํ๋ค.
<html> <body> <ul id="home"> <li id="conan">Conan</li> <li id="mocha">Mocha</li> <li id="stuckyi">Stuckyi</li> </ul> </body> </html>
- ์์ ์์ ์์ ul์์์ ๋ ๋ฒ์งธ ์์ ์์์ธ li๋ฅผ ํด๋ฆญํ๋ฉด ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ๋ค. ์ด ๋ ์์ฑ๋ ์ด๋ฒคํธ ๊ฐ์ฒด๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ DOM์์์ธ ์ด๋ฒคํธ ํ๊น์ ์ค์ฌ์ผ๋ก DOM ํธ๋ฆฌ๋ฅผ ํตํด ์ ํ๋๋ค.
- ์ด๋ฒคํธ ์ ํ๋ ์ด๋ฒคํธ ๊ฐ์ฒด๊ฐ ์ ํ๋๋ ๋ฐฉํฅ์ ๋ฐ๋ผ ๋ค์๊ณผ ๊ฐ์ด 3๋จ๊ณ๋ก ๊ตฌ์ฑ๋๋ค.
- ์บก์ฒ๋ง ๋จ๊ณ(capturing phase) : ์ด๋ฒคํธ๊ฐ ์์ ์์์์ ํ์ ์์ ๋ฐฉํฅ์ผ๋ก ์ ํ
- ํ๊น ๋จ๊ณ(target phase) : ์ด๋ฒคํธ๊ฐ ์ด๋ฒคํธ ํ๊น์ ๋๋ฌ
- ๋ฒ๋ธ๋ง ๋จ๊ณ(bubbling phase) : ์ด๋ฒคํธ๊ฐ ํ์ ์์์์ ์์ ์์ ๋ฐฉํฅ์ผ๋ก ์ ํ
-
ul ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฐ์ธ๋ฉํ๊ณ ul ์์์ ํ์ ์์์ธ li์์๋ฅผ ํด๋ฆญํ์ฌ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์์ผ ๋ณด์.
<html> <body> <ul id="home"> <li id="conan">Conan</li> <li id="mocha">Mocha</li> <li id="stuckyi">Stuckyi</li> </ul> </body> <script> const home = document.getElementById("home"); //home ์์์ ํ์ ์์์ธ li๋ฅผ ํด๋ฆญํ ๊ฒฝ์ฐ home.addEventListener("click", (e) => { console.log(`์ด๋ฒคํธ ๋จ๊ณ: ${e.eventPhase}`); //์ด๋ฒคํธ ๋จ๊ณ: 3 : ๋ฒ๋ธ๋ง ๋จ๊ณ console.log(`์ด๋ฒคํธ ํ๊น: ${e.target}`); //[object HTMLLIElement] console.log(`์ปค๋ฐํธ ํ๊น: ${e.currentTarget}`); //[object HTMLUListElement] }); </script> </html>
- li ์์๋ฅผ ํด๋ฆญํ๋ฉด ํด๋ฆญ ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ์ฌ ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ฒด๊ฐ ์์ฑ๋๊ณ ํด๋ฆญ๋ li ์์๊ฐ ์ด๋ฒคํธ ํ๊น์ด ๋๋ค.
- ์ด ๋ ํด๋ฆญ ์ด๋ฒคํธ ๊ฐ์ฒด๋ window์์ ์์ํด์ ์ด๋ฒคํธ ํ๊น์ผ๋ก ์ ํ๋๋ค. (์บก์ณ๋ง ๋จ๊ณ)
- ์ด ํ ์ด๋ฒคํธ ๊ฐ์ฒด๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ ์ด๋ฒคํธ ํ๊น์ ๋์ฐฉํ๋ค. (ํ๊น ๋จ๊ณ)
- ์ด ํ ์ด๋ฒคํธ ๊ฐ์ฒด๋ ์ด๋ฒคํธ ํ๊น์์ ์์ํด์ window ๋ฐฉํฅ์ผ๋ก ์ ํ๋๋ค. (๋ฒ๋ธ๋ง ๋จ๊ณ)
-
์ด๋ฒคํธ ํธ๋ค๋ฌ ์ดํธ๋ฆฌ๋ทฐํธ/ํ๋กํผํฐ ๋ฐฉ์์ผ๋ก ๋ฑ๋กํ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํ๊น ๋จ๊ณ์ ๋ฒ๋ธ๋ง ๋จ๊ณ๋ง ์บ์นํ ์ ์๋ค. ํ์ง๋ง, addEventListener ๋ฉ์๋ ๋ฐฉ์์ผ๋ก ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ ํ๊น ๋จ๊ณ์ ๋ฒ๋ธ๋ง ๋จ๊ณ ๋ฟ ์๋๋ผ ์บก์ณ๋ง ๋จ๊ณ์ ์ด๋ฒคํธ๋ ์ ๋ณ์ ์ผ๋ก ์บ์นํ ์ ์๋ค.
-
์บก์ฒ๋ง ๋จ๊ณ์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ์ฌ๋ฉด addEventListener ๋ฉ์๋์ 3๋ฒ์งธ ์ธ์๋ก true์ ์ ๋ฌํด์ผ ํ๋ค. 3๋ฒ์งธ ์ธ์๋ฅผ ์๋ตํ๊ฑฐ๋ false๋ฅผ ์ ๋ฌํ๋ฉด ํ๊น ๋จ๊ณ์ ๋ฒ๋ธ๋ง ๋จ๊ณ์ ์ด๋ฒคํธ๋ง ์บ์นํ ์ ์๋ค.
<html> <body> <ul id="home"> <li id="conan">Conan</li> <li id="mocha">Mocha</li> <li id="stuckyi">Stuckyi</li> </ul> </body> <script> const home = document.getElementById("home"); const mocha = document.getElementById("mocha"); //home ์์์ ํ์ ์์์ธ li๋ฅผ ํด๋ฆญํ ๊ฒฝ์ฐ ์บก์ณ๋ง ๋จ๊ณ์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๋ค. home.addEventListener("click", (e) => { console.log(`์ด๋ฒคํธ ๋จ๊ณ: ${e.eventPhase}`); //์ด๋ฒคํธ ๋จ๊ณ: 1 : ์บก์ณ๋ง ๋จ๊ณ console.log(`์ด๋ฒคํธ ํ๊น: ${e.target}`); //์ด๋ฒคํธ ํ๊น: [object HTMLLIElement] console.log(`์ปค๋ฐํธ ํ๊น: ${e.currentTarget}`); //์ปค๋ฐํธ ํ๊น: [object HTMLUListElement] },true); //ํ๊น ๋จ๊ณ์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๋ค. mocha.addEventListener("click", (e) => { console.log(`์ด๋ฒคํธ ๋จ๊ณ: ${e.eventPhase}`); //์ด๋ฒคํธ ๋จ๊ณ: 2 : ํ๊น ๋จ๊ณ console.log(`์ด๋ฒคํธ ํ๊น: ${e.target}`); //์ด๋ฒคํธ ํ๊น: [object HTMLLIElement] console.log(`์ปค๋ฐํธ ํ๊น: ${e.currentTarget}`); //์ปค๋ฐํธ ํ๊น: [object HTMLLIElement] }); //๋ฒ๋ธ๋ง ๋จ๊ณ์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ๋ค. home.addEventListener("click", (e) => { console.log(`์ด๋ฒคํธ ๋จ๊ณ: ${e.eventPhase}`); //์ด๋ฒคํธ ๋จ๊ณ: 3 : ๋ฒ๋ธ๋ง ๋จ๊ณ console.log(`์ด๋ฒคํธ ํ๊น: ${e.target}`); //์ด๋ฒคํธ ํ๊น: [object HTMLLIElement] console.log(`์ปค๋ฐํธ ํ๊น: ${e.currentTarget}`); //์ปค๋ฐํธ ํ๊น: [object HTMLUListElement] }); </script> </html>
- ์ด์ฒ๋ผ ์ด๋ฒคํธ๋ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์ํจ ์ด๋ฒคํธ ํ๊น์ ๋ฌผ๋ก ์์ DOM์์์์๋ ์บ์นํ ์ ์๋ค.
- ๋๋ถ๋ถ์ ์ด๋ฒคํธ๋ ์บก์ฒ๋ง๊ณผ ๋ฒ๋ธ๋ง์ ํตํด ์ ํ๋๋ค. ํ์ง๋ง ๋ช๋ช ์ด๋ฒคํธ๋ ๋ฒ๋ธ๋ง์ ํตํด ์ ํ๋์ง ์๋๋ค.
-
์ฌ๋ฌ๊ฐ์ ํ์ DOM ์์์ ๊ฐ๊ฐ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ ๋์ ํ๋์ ์์ DOM ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ ๋ฐฉ๋ฒ์ ๋งํ๋ค.
-
์๋์ ์์ ๋ฅผ ๋ณด์.
<!DOCTYPE html> <html> <head> <style> #home { display: flex; list-style-type: none; padding: 0; } #home li { width: 100px; cursor: pointer; } #home .active { color: aqua; text-decoration: underline; } </style> </head> <body> <ul id="home"> <li id="conan">Conan</li> <li id="mocha">Mocha</li> <li id="stuckyi">Stuckyi</li> </ul> <nav>์ ํ๋ ๊ฐ์กฑ : <em class="msg">Conan</em></nav> </body> <script> const home = document.getElementById("home"); const msg = document.querySelector(".msg"); //์ฌ์ฉ์ ํด๋ฆญ์ ์ํด ์ ํ๋ ๊ฐ์กฑ (li์์)์ active ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ณ //๊ทธ ์ธ์ ๋ชจ๋ ๊ตฌ์ฑ์์ active ํด๋์ค๋ฅผ ์ ๊ฑฐํ๋ค. function activate({ target }) { [...home.children].forEach((home) => { home.classList.toggle("active", home === target); msg.textContent = target.id; }); } //๋ชจ๋ ๊ตฌ์ฑ์ (li์์)์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ค. document.getElementById("conan").onclick = activate; document.getElementById("mocha").onclick = activate; document.getElementById("stuckyi").onclick = activate; </script> </html>
-
๋ชจ๋ li ์์๊ฐ ํด๋ฆญ ์ด๋ฒคํธ์ ๋ฐ์ํ๋๋ก ๋ชจ๋ li ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ์ธ activate๋ฅผ ๋ฑ๋กํ๋ค.
-
๋ง์ฝ li ์์๊ฐ 1000๊ฐ๋ผ๋ฉด ?
-
์ด ๊ฒฝ์ฐ ๋ง์ DOM ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๋ฏ๋ก ์ฑ๋ฅ ์ ํ์ ์์ธ์ด ๋ ๋ฟ๋๋ฌ ์ ์ง๋ณด์์๋ ๋ถ์ ํฉํ ์ฝ๋๋ฅผ ์์ฑํ๊ฒ ๋๋ค.
-
์ด๋ฒคํธ ์์์ ์์ฉํ์ฌ ์์ ํด ๋ณด์.
<!DOCTYPE html> <html> <head> <style> #home { display: flex; list-style-type: none; padding: 0; } #home li { width: 100px; cursor: pointer; } #home .active { color: aqua; text-decoration: underline; } </style> </head> <body> <ul id="home"> <li id="conan">Conan</li> <li id="mocha">Mocha</li> <li id="stuckyi">Stuckyi</li> </ul> <nav>์ ํ๋ ๊ฐ์กฑ : <em class="msg">Conan</em></nav> </body> <script> const home = document.getElementById("home"); const msg = document.querySelector(".msg"); //์ฌ์ฉ์ ํด๋ฆญ์ ์ํด ์ ํ๋ ๊ฐ์กฑ (li์์)์ active ํด๋์ค๋ฅผ ์ถ๊ฐํ๊ณ //๊ทธ ์ธ์ ๋ชจ๋ ๊ตฌ์ฑ์์ active ํด๋์ค๋ฅผ ์ ๊ฑฐํ๋ค. function activate({ target }) { //์ด๋ฒคํธ๋ฅผ ๋ฐ์๊ธฐํจ ์์ (target)๊ฐ ul#home์ ์์ ์์๊ฐ ์๋๋ผ๋ฉด ๋ฌด์ํ๋ค. if (!target.matches("#home > li")) return; [...home.children].forEach((home) => { home.classList.toggle("active", home === target); msg.textContent = target.id; }); } //์ด๋ฒคํธ ์์ : ์์ ์์ (ul#home)๋ ํ์ ์์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ ์ ์๋ค. home.onclick = activate; </script> </html>
Element.prototype.matches : ์ธ์๋ก ์ ๋ฌ๋ ์ ํ์์ ์ํด ํน์ ๋ ธ๋๋ฅผ ํ์ ๊ฐ๋ฅํ์ง ํ์ธํ๋ค.
- ์ด๋ฒคํธ ์์์ ํตํด ํ์ DOM ์์์์ ๋ฐ์ํ ์ด๋ฒคํธ๋ฅผ ์ฒ๋ฆฌํ ๋ ์ฃผ์ํ ์ ์ ์์ ์์์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ๋ฑ๋กํ๊ธฐ ๋๋ฌธ์ ์ด๋ฒคํธ ํ๊น, ์ฆ ์ค์ ๋ก ๋ฐ์์ํจ DOM ์์๊ฐ ์ฐ๋ฆฌ๊ฐ ๊ธฐ๋ํ DOM์์๊ฐ ์๋ ์ ์๋ค๋ ๊ฒ์ด๋ค.
- ๋ฐ๋ผ์ ์ด๋ฒคํธ์ ๋ฐ์์ด ํ์ํ DOM ์์ (#home > li)์ ํ์ ํ์ฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์คํ๋๋๋ก ์ด๋ฒคํธ ํ๊น์ ๊ฒ์ฌํด์ผ ํ๋ค.
-
-
DOM ์์์ ๊ธฐ๋ณธ ๋์์ ์ค์ง ์ํจ๋ค.
document.querySelector("a").onclick = e => { //a ์์์ ๊ธฐ๋ณธ ๋์์ ์ค์งํ๋ค. e.preventDefault(); } document.querySelector("input[type=checkbox]").onclick = e => { //checkbox ์์์ ๊ธฐ๋ณธ ๋์์ ์ค์งํ๋ค. e.preventDefault(); }
-
์ด๋ฒคํธ ์ ํ๋ฅผ ์ค์ง์ํจ๋ค.
<!DOCTYPE html> <html> <body> <div class="container"> <button class="btn1">btn1</button> <button class="btn2">btn2</button> <button class="btn3">btn3</button> </div> <script> //์ด๋ฒคํธ ์์. ํด๋ฆญ๋ ํ์ ์์์ color๋ฅผ ๋ณ๊ฒฝํ๋ค. document.querySelector(".container").onclick = ({ target }) => { if (!target.matches(".container > button")) return; target.style.color = "blue"; }; //.btn2 ์์๋ ์ด๋ฒคํธ๋ฅผ ์ ํํ์ง ์์ผ๋ฏ๋ก ์์ ์์์์ ์ด๋ฒคํธ๋ฅผ ์บ์นํ ์ ์๋ค. document.querySelector(".btn2").onclick = (e) => { e.stopPropagation(); e.target.style.color = "red"; }; </script> </body> </html>
์ฐธ๊ณ : ๋ชจ๋ ์๋ฐ์คํฌ๋ฆฝํธ deep dive