** ๐DOM(Document Object Model) ์ด๋?**
HTML ๋ฌธ์๋ฅผ ๊ฐ์ฒด๋ก ํํํ ๊ตฌ์กฐ โ ๋ธ๋ผ์ฐ์ ๊ฐ ์ดํดํ ์ ์๋ ํธ๋ฆฌ
- HTML์ ๊ฐ์ฒดํ โ JS๋ก ์ง์ ์กฐ์ ๊ฐ๋ฅ
- ํธ๋ฆฌ(Tree) ๊ตฌ์กฐ๋ก ๊ณ์ธตํ โ ๋ถ๋ชจ-์์ ๊ด๊ณ
2๏ธโฃ ๐ณ DOM ํธ๋ฆฌ ๊ตฌ์กฐ (์๊ฐํ)
<body>
<div id="container">
<p>Hello</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</div>
</body>
php-template
๋ณต์ฌํธ์ง
Document
โโโ <html>
โโโ <body>
โโโ <div id="container">
โโโ <p>
โโโ <ul>
โโโ <li>
โโโ <li>
- Document โ Element โ Text โ Attribute โ Comment๋ก ๊ตฌ์ฑ
3๏ธโฃ ๐ DOM ํ์ (๊ธฐ์ด + ์ฌํ)
๐ ๊ธฐ๋ณธ ํ์ ๋ฉ์๋
๋ฉ์๋ |
์ค๋ช
|
getElementById |
id๋ก ํ์ |
getElementsByClassName |
class๋ก ํ์ (HTMLCollection) |
querySelector |
CSS ์ ํ์ ๊ธฐ๋ฐ ํ์ (์ต์ด ํ๋) |
querySelectorAll |
CSS ์ ํ์ ๊ธฐ๋ฐ ๋ชจ๋ ์์ (NodeList) |
โ
์ฌํ ํ์ ๋ฉ์๋
๋ฉ์๋ |
์ค๋ช
|
parentNode / parentElement |
๋ถ๋ชจ ์์ ํ์ |
children |
์์ ์์(HTMLCollection) |
firstElementChild / lastElementChild |
์ฒซ/๋ง์ง๋ง ์์ |
nextElementSibling / previousElementSibling |
ํ์ ๋
ธ๋ ํ์ |
๐ฏ ์ฌํ ์์
javascript
๋ณต์ฌํธ์ง
const container = document.getElementById('container');
console.log(container.children); // ul, p
console.log(container.parentElement); // body
console.log(container.firstElementChild); // <p
4๏ธโฃ ๐ ๏ธ DOM ์์ /์ถ๊ฐ/์ญ์ ์ฌํ ํจํด
์์
|
๋ฉ์๋ |
๋ด์ฉ ์์ |
element.textContent , innerHTML |
์์ฑ ์์ |
setAttribute , classList |
์์ ์ถ๊ฐ |
appendChild , insertBefore , insertAdjacentHTML |
์์ ์ญ์ |
removeChild , remove() |
๐ ์ค๋ฌด ์ต์ ํ ํจํด
// ๊ธฐ์กด ์์๋ฅผ ์ ๊ฑฐ ํ ์ฌ์ฝ์
โ ์ฑ๋ฅ ์ ํ
document.body.innerHTML += '<div>New</div>'; // โ
// DocumentFragment ์ฌ์ฉ โ ์ฑ๋ฅ ํฅ์
const frag = document.createDocumentFragment();
const newDiv = document.createElement('div');
newDiv.textContent = 'New';
frag.appendChild(newDiv);
document.body.appendChild(frag); // โ
5๏ธโฃ ๐ฏ ์ด๋ฒคํธ(Event) ๊ธฐ๋ณธ
์ฉ์ด |
์ค๋ช
|
Event |
์ฌ์ฉ์ ์
๋ ฅ or ์์คํ
๋ฐ์ ํ๋ (ํด๋ฆญ, ์คํฌ๋กค ๋ฑ) |
Event Listener |
์ด๋ฒคํธ ๋ฐ์ ์ ์คํํ ํจ์ ๋ฑ๋ก |
โ
๊ธฐ์ด ์์
const btn = document.querySelector('button');
btn.addEventListener('click', () => console.log('Button clicked!'));
6๏ธโฃ ๐ฅ ์ด๋ฒคํธ ๋ฒ๋ธ๋ง & ์บก์ฒ๋ง ์ฌํ
๐ ์ ํ ๊ณผ์ :
1. Capturing Phase (์ต์์ โ ํ๊ฒ)
2. Target Phase (์ด๋ฒคํธ ๋ฐ์)
3. Bubbling Phase (ํ๊ฒ โ ์ต์์)
๐ ๊ฐ์์ ๋์
<body>
<div>
<button>Click</button>
</div>
</body>
Click โ
1. body (์บก์ฒ๋ง)
2. div (์บก์ฒ๋ง)
3. button (ํ๊ฒ)
4. div (๋ฒ๋ธ๋ง)
5. body (๋ฒ๋ธ๋ง)
โ
์บก์ฒ๋ง ์ค์
document.body.addEventListener('click', () => console.log('Capturing'), true);
๋ฉด์ ํฌ์ธํธ:
โ๋ฒ๋ธ๋ง๊ณผ ์บก์ฒ๋ง์ ์ฐจ์ด์, ์ค๋ฌด์์ ์บก์ฒ๋ง์ ์ธ์ ์ฌ์ฉํ๋๊ฐ?โ
โ ๊ธฐ๋ณธ์ ๋ฒ๋ธ๋ง, ํน์ํ ๊ฒฝ์ฐ ์ ํ ์์ ์ ์ด ์ํด ์บก์ฒ๋ง
7๏ธโฃ ๐ซ stopPropagation & preventDefault ์ฌํ
๋ฉ์๋ |
์ญํ |
stopPropagation |
์ด๋ฒคํธ ์ ํ ์ฐจ๋จ (์์๋ก ์ ์ฌ๋ผ๊ฐ) |
stopImmediatePropagation |
ํ์ฌ ์์ ๋ด ๋ชจ๋ ํธ๋ค๋ฌ ์คํ ์ค๋จ |
preventDefault |
๊ธฐ๋ณธ ๋์(๋งํฌ ์ด๋, ํผ ์ ์ถ ๋ฑ) ์ฐจ๋จ |
โ
์ฌํ ์์
const link = document.querySelector('a');
link.addEventListener('click', (e) => {
e.preventDefault(); // ๋งํฌ ์ด๋ X
e.stopPropagation(); // ์์ ์ ํ X
});
8๏ธโฃ ๐ง ์ด๋ฒคํธ ์์ ์ฌํ ์ค๋ฌด ํจํด
๋ถ๋ชจ ์์์ ์ด๋ฒคํธ๋ฅผ ๊ฑธ๊ณ , ์์์ ์ด๋ฒคํธ๋ฅผ ํ ๋ฒ์ ์ฒ๋ฆฌ โ ์ฑ๋ฅ ์ต์ ํ
โ
๊ธฐ๋ณธ ์์
document.querySelector('#list').addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('active');
}
});
๐ ์ฌํ: ๋์ ์์ ๊ด๋ฆฌ + ์์ ํ์ฉ
const list = document.querySelector('#list');
// ๋์ ์ผ๋ก ์์ ์ถ๊ฐ
const newItem = document.createElement('li');
newItem.textContent = 'New Item';
list.appendChild(newItem);
// ์ด๋ฏธ ๋ถ๋ชจ์ ๋ฑ๋ก๋ ์ด๋ฒคํธ ๋ฆฌ์ค๋๋ก ์ฒ๋ฆฌ OK!
9๏ธโฃ โก ์ค๋ฌด ์ฑ๋ฅ ์ต์ ํ ํจํด
์ํฉ |
์ต์ ํ ๋ฐฉ๋ฒ |
๋ง์ ์์์ ์ด๋ฒคํธ ๋ฆฌ์ค๋ |
๋ถ๋ชจ์ ์ด๋ฒคํธ ์์ ์ ์ฉ |
DOM ์กฐ์ ๋ง์ ๋ |
DocumentFragment ์ฌ์ฉ โ ๋ฆฌํ๋ก์ฐ ์ต์ํ |
๊ณ ๋น๋ ์ด๋ฒคํธ (scroll, resize) |
Throttle/Debounce ์ ์ฉ |
๋์ ์์ ๋ง์ ๋ |
MutationObserver + ์ด๋ฒคํธ ์์ ์กฐํฉ ํ์ฉ |
๐ ๐ง ๊ธฐ์ ๋ฉด์ ๋๋น ํต์ฌ ์ ๋ฆฌ
์ง๋ฌธ |
ํต์ฌ ๋ต๋ณ |
DOM์ด๋? |
HTML ๋ฌธ์๋ฅผ ๊ฐ์ฒด๋ก ํํํ ํธ๋ฆฌ ๊ตฌ์กฐ |
DOM ํ์ ๋ฐฉ๋ฒ? |
getElementById, querySelector, parentNode ๋ฑ |
๋ฒ๋ธ๋ง vs ์บก์ฒ๋ง ์ฐจ์ด? |
์ ํ ๋ฐฉํฅ: ํ์โ์์ vs ์์โํ์ |
stopPropagation๊ณผ preventDefault ์ฐจ์ด? |
์ ํ ์ค๋จ vs ๊ธฐ๋ณธ ๋์ ์ทจ์ |
์ด๋ฒคํธ ์์ ์ฅ์ ? |
๋ฆฌ์ค๋ ๋ถํ โ, ๋์ ์์ ๊ด๋ฆฌ ์ฌ์ |
์ค๋ฌด์์ DOM ์กฐ์ ์ฑ๋ฅ ๊ฐ์ ๋ฐฉ๋ฒ? |
Fragment, ์ด๋ฒคํธ ์์, Throttle, MutationObserver |
๐ ์ข
ํฉ์ฝ๋ ์์
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>JavaScript ๋น๋๊ธฐ & DOM ์กฐ์ ์ฌํ ์ค์ต</title>
<style>
.area {
background: lightgray;
border: 1px solid black;
width: 600px;
margin-bottom: 10px;
padding: 10px;
white-space: pre-wrap;
font-family: monospace;
}
.big { height: 600px; overflow-y: scroll; }
</style>
</head>
<body>
<h2>๐ข JavaScript ๋น๋๊ธฐ & DOM ์กฐ์ ์ฌํ ์ค์ต</h2>
<div class="area big" id="outputArea"></div>
<script>
function runExamples() {
const output = document.getElementById("outputArea");
function log(text) { output.innerHTML += text + "\n"; }
// โ
DOM ์กฐ์ ๊ธฐ๋ณธ
log("โ
DOM ์กฐ์ ๊ธฐ๋ณธ");
document.body.innerHTML += '<div id="container"><p>Hello</p><ul><li>Item 1</li><li>Item 2</li></ul></div>';
// โ
DOM ํ์ ์์
log("\nโ
DOM ํ์ ์์ ");
const container = document.getElementById('container');
log("children: " + container.children.length); // ์์ ์์ ๊ฐ์
log("parent: " + container.parentElement.tagName); // ๋ถ๋ชจ ์์ ํ๊ทธ๋ช
log("first child: " + container.firstElementChild.tagName); // ์ฒซ ๋ฒ์งธ ์์ ์์ ํ๊ทธ๋ช
// โ
DOM ์์ /์ถ๊ฐ/์ญ์ ์์
log("\nโ
DOM ์์ /์ถ๊ฐ/์ญ์ ์์ ");
const newItem = document.createElement('li');
newItem.textContent = 'New Item';
container.querySelector('ul').appendChild(newItem);
log("์ ์์ดํ
์ถ๊ฐ๋จ: " + newItem.textContent);
// โ
์ด๋ฒคํธ ํธ๋ค๋ง ๊ธฐ๋ณธ
log("\nโ
์ด๋ฒคํธ ํธ๋ค๋ง ๊ธฐ๋ณธ");
const btn = document.createElement('button');
btn.textContent = 'ํด๋ฆญํ์ธ์';
document.body.appendChild(btn);
btn.addEventListener('click', () => log('๋ฒํผ ํด๋ฆญ๋จ!'));
// โ
์ด๋ฒคํธ ๋ฒ๋ธ๋ง & ์บก์ฒ๋ง
log("\nโ
์ด๋ฒคํธ ๋ฒ๋ธ๋ง & ์บก์ฒ๋ง");
document.body.addEventListener('click', () => log('๐ ์บก์ฒ๋ง ๋จ๊ณ'), true);
document.body.addEventListener('click', () => log('๐ ๋ฒ๋ธ๋ง ๋จ๊ณ'));
// โ
stopPropagation & preventDefault ์์
log("\nโ
stopPropagation & preventDefault ์์ ");
const link = document.createElement('a');
link.href = "#";
link.textContent = "ํด๋ฆญ ๊ธ์ง ๋งํฌ";
document.body.appendChild(link);
link.addEventListener('click', (e) => {
e.preventDefault(); // ๊ธฐ๋ณธ ๋์(์ด๋) ์ฐจ๋จ
e.stopPropagation(); // ์ด๋ฒคํธ ์ ํ ์ฐจ๋จ
log("โ ๋งํฌ ํด๋ฆญ ์ฐจ๋จ๋จ");
});
// โ
์ด๋ฒคํธ ์์ ํจํด
log("\nโ
์ด๋ฒคํธ ์์ ํจํด");
const list = document.createElement('ul');
list.innerHTML = '<li>Item A</li><li>Item B</li>';
document.body.appendChild(list);
list.addEventListener('click', (e) => {
if (e.target.tagName === 'LI') {
e.target.classList.toggle('active'); // ํด๋์ค ํ ๊ธ
log("๐ " + e.target.textContent + " ์ ํ๋จ");
}
});
// โ
์ค๋ฌด ์ฑ๋ฅ ์ต์ ํ
log("\nโ
์ค๋ฌด ์ฑ๋ฅ ์ต์ ํ");
const frag = document.createDocumentFragment();
for (let i = 0; i < 5; i++) {
const div = document.createElement('div');
div.textContent = 'Batch ' + i;
frag.appendChild(div); // DocumentFragment์ ์ถ๊ฐ
}
document.body.appendChild(frag); // ํ ๋ฒ์ ์ถ๊ฐ (๋ฆฌํ๋ก์ฐ ์ต์ํ)
log("๐ DocumentFragment๋ก ๋ฐฐ์น ์ฒ๋ฆฌ ์๋ฃ");
// โ
MutationObserver๋ฅผ ํ์ฉํ ๋์ ์์ ๊ฐ์ง
log("\nโ
MutationObserver ํ์ฉ ์์ ");
const observerTarget = document.createElement('div');
observerTarget.id = 'observerTarget';
document.body.appendChild(observerTarget);
const observer = new MutationObserver(mutations => {
mutations.forEach(mutation => {
log("โก ๋ณ๊ฒฝ ๊ฐ์ง๋จ: " + mutation.type);
});
});
observer.observe(observerTarget, { childList: true, subtree: true });
setTimeout(() => {
const newElement = document.createElement('p');
newElement.textContent = '๐ ๊ฐ์ง๋ ์์';
observerTarget.appendChild(newElement);
}, 2000);
}
runExamples();
</script>
</body>
</html>
๐ ์ด๋ฒคํธ ์ฝ๋ ์์
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JavaScript ์ด๋ฒคํธ ์์ ์ ๋ณต ๐</title>
<style>
.area {
width: 100%;
height: 50px;
border: 1px solid #333;
margin-top: 10px;
padding: 5px;
background-color: #f9f9f9;
}
.highlight {
background-color: yellow;
}
</style>
</head>
<body>
<h1>๐ ์ด๋ฒคํธ(Event) ์๋ฒฝ ๊ฐ์ด๋</h1>
<!-- 1๏ธโฃ ์ธ๋ผ์ธ ์ด๋ฒคํธ -->
<h3>1๏ธโฃ ์ธ๋ผ์ธ ์ด๋ฒคํธ ๋ฐฉ์</h3>
<button onclick="inlineEvent()">๐ฅ ์ธ๋ผ์ธ ์คํํ์ธ</button>
<!-- 2๏ธโฃ ์์ฑ์ผ๋ก ํธ๋ค๋ฌ ์ฐ๊ฒฐ -->
<h3>2๏ธโฃ ์์ฑ ๋ฐฉ์ (DOM ํ๋กํผํฐ ๋ฐฉ์)</h3>
<button id="btn1">โ
์์ฑ ๋ฐฉ์ ์คํ</button>
<div id="area1" class="area"></div>
<!-- 3๏ธโฃ addEventListener -->
<h3>3๏ธโฃ addEventListener ๋ฐฉ์ (ํ์ค ์ด๋ฒคํธ ๋ชจ๋ธ)</h3>
<button id="btn2">๐ฏ addEventListener ์คํ</button>
<div id="area2" class="area"></div>
<!-- 4๏ธโฃ ์ด๋ฒคํธ ๊ฐ์ฒด + this -->
<h3>4๏ธโฃ ์ด๋ฒคํธ ๊ฐ์ฒด & this ์ดํด</h3>
<button id="btn3">๐ ์ด๋ฒคํธ ๊ฐ์ฒด ํ์ธ</button>
<div id="area3" class="area"></div>
<!-- 5๏ธโฃ ์ด๋ฒคํธ ์์ -->
<h3>5๏ธโฃ ์ด๋ฒคํธ ์์ (Event Delegation)</h3>
<div id="parentArea" class="area">
<button class="child-btn">๋์ ๋ฒํผ1</button>
<button class="child-btn">๋์ ๋ฒํผ2</button>
</div>
<button id="addBtn">โ ๋์ ๋ฒํผ ์ถ๊ฐ</button>
<!-- 6๏ธโฃ ๊ณ ๊ธ - ์ด๋ฒคํธ ์ ๊ฑฐ & once ์ต์
-->
<h3>6๏ธโฃ ๊ณ ๊ธ - removeEventListener & once ์ต์
</h3>
<button id="btn4">๐๏ธ ํธ๋ค๋ฌ ํ ๋ฒ ์คํ ํ ์ ๊ฑฐ</button>
<div id="area4" class="area"></div>
<!-- 7๏ธโฃ preventDefault & stopPropagation -->
<h3>7๏ธโฃ ๊ธฐ๋ณธ ๋์ ๋ฐฉ์ง & ์ด๋ฒคํธ ์ ํ ์ค๋จ</h3>
<form id="myForm">
<input type="text" placeholder="์๋ฌด๊ฑฐ๋ ์
๋ ฅ ํ ์ํฐ" />
<button type="submit">๐ซ ์ ์ถ</button>
</form>
<div id="area5" class="area"></div>
<!-- 8๏ธโฃ ์ปค์คํ
์ด๋ฒคํธ -->
<h3>8๏ธโฃ ์ปค์คํ
์ด๋ฒคํธ ์์ฑ & ์ฌ์ฉ</h3>
<button id="btn5">โจ ์ปค์คํ
์ด๋ฒคํธ ์คํ</button>
<div id="area6" class="area"></div>
<script>
/***********************************
1๏ธโฃ ์ธ๋ผ์ธ ์ด๋ฒคํธ ๋ฐฉ์ - HTML์ ์ง์ ์ง์
************************************/
function inlineEvent() {
alert("๐ฅ ์ธ๋ผ์ธ ์ด๋ฒคํธ ๋ฐ์!");
}
/***********************************
2๏ธโฃ ์์ฑ ๋ฐฉ์ (DOM ํ๋กํผํฐ์ ํจ์ ํ ๋น)
************************************/
const btn1 = document.getElementById("btn1");
const area1 = document.getElementById("area1");
btn1.onclick = function() {
area1.textContent = "โ
์์ฑ ๋ฐฉ์ ์ด๋ฒคํธ ์คํ!";
area1.style.backgroundColor = "#d4edda";
};
/***********************************
3๏ธโฃ addEventListener ๋ฐฉ์ (๋ค์ค ํธ๋ค๋ฌ ๊ฐ๋ฅ)
************************************/
const btn2 = document.getElementById("btn2");
const area2 = document.getElementById("area2");
btn2.addEventListener("click", function() {
area2.textContent = "๐ฏ ์ฒซ ๋ฒ์งธ ํธ๋ค๋ฌ ์คํ!";
area2.style.backgroundColor = "#cce5ff";
});
btn2.addEventListener("click", function() {
console.log("โ
๋ ๋ฒ์งธ ํธ๋ค๋ฌ๋ ์คํ๋จ!");
});
/***********************************
4๏ธโฃ ์ด๋ฒคํธ ๊ฐ์ฒด(event) & this ์ดํด
************************************/
const btn3 = document.getElementById("btn3");
const area3 = document.getElementById("area3");
btn3.addEventListener("click", function(event) {
console.log("๐ ์ด๋ฒคํธ ํ์
:", event.type); // ํด๋ฆญ ํ์
console.log("๐ ํด๋ฆญํ ์์:", event.target); // ํด๋ฆญ ๋์
this.style.backgroundColor = "pink"; // this๋ btn3 ๊ฐ๋ฆฌํด
area3.innerHTML = `
<strong>์ด๋ฒคํธ ํ์
:</strong> ${event.type}<br/>
<strong>ํด๋ฆญํ ์์:</strong> ${event.target.textContent}
`;
});
/***********************************
5๏ธโฃ ์ด๋ฒคํธ ์์ (๋ถ๋ชจ์๊ฒ ์ด๋ฒคํธ ์ฐ๊ฒฐ)
************************************/
const parentArea = document.getElementById("parentArea");
const addBtn = document.getElementById("addBtn");
parentArea.addEventListener("click", function(event) {
if (event.target.classList.contains("child-btn")) {
event.target.classList.toggle("highlight"); // ๊ฐ์กฐ ํ ๊ธ
alert(`๐ฝ ${event.target.textContent} ํด๋ฆญ๋จ!`);
}
});
addBtn.addEventListener("click", function() {
const newBtn = document.createElement("button");
newBtn.textContent = `๋์ ๋ฒํผ${parentArea.children.length + 1}`;
newBtn.classList.add("child-btn");
parentArea.appendChild(newBtn);
});
/***********************************
6๏ธโฃ ์ด๋ฒคํธ ์ ๊ฑฐ & once ์ต์
************************************/
const btn4 = document.getElementById("btn4");
const area4 = document.getElementById("area4");
// ๋ฐฉ๋ฒ1 - once ์ต์
: ํ ๋ฒ๋ง ์คํ ํ ์๋ ์ ๊ฑฐ
btn4.addEventListener("click", function() {
area4.textContent = "๐๏ธ ํ ๋ฒ๋ง ์คํ ํ ์ ๊ฑฐ๋จ!";
area4.style.backgroundColor = "#ffeeba";
}, { once: true });
// ๋ฐฉ๋ฒ2 - removeEventListener (์ค๋ช
์ฉ, ๋ฐ๋ก ์ฌ์ฉํ๋ ค๋ฉด ํธ๋ค๋ฌ ๋ณ์ํ ํ์)
/***********************************
7๏ธโฃ preventDefault & stopPropagation
************************************/
const myForm = document.getElementById("myForm");
const area5 = document.getElementById("area5");
myForm.addEventListener("submit", function(event) {
event.preventDefault(); // ํผ ๊ธฐ๋ณธ ์ ์ถ ๋ง๊ธฐ ๐ซ
area5.textContent = "๐ซ ๊ธฐ๋ณธ ์ ์ถ ๋ฐฉ์ง๋จ!";
area5.style.backgroundColor = "#f8d7da";
});
/***********************************
8๏ธโฃ ์ปค์คํ
์ด๋ฒคํธ ๋ง๋ค๊ธฐ
************************************/
const btn5 = document.getElementById("btn5");
const area6 = document.getElementById("area6");
// ์ปค์คํ
์ด๋ฒคํธ ์ ์
const customEvent = new CustomEvent("shine", {
detail: { message: "โจ ์ปค์คํ
์ด๋ฒคํธ ๋ฐ์!" }
});
// ์ด๋ฒคํธ ๋ฆฌ์ค๋
btn5.addEventListener("shine", function(e) {
console.log(e.detail.message);
area6.textContent = e.detail.message;
area6.style.backgroundColor = "#e2e3e5";
});
// ํด๋ฆญ ์ ์ปค์คํ
์ด๋ฒคํธ ๋ฐ์
btn5.addEventListener("click", function() {
btn5.dispatchEvent(customEvent); // ์ปค์คํ
์ด๋ฒคํธ ์คํ
});
</script>
</body>
</html>