SEB FE / Section1 / Unit10 / JS/Browser DOM
๐ Today I Learned
- DOM
DOM์ด๋ Document Object Model์
๋๋ค. document๋ฅผ ๊ฐ์ฒด๋ก ๊ตฌํํ๋ค๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค.
DOM์ Document Object Model์ ์ฝ์๋ก, HTML ์์๋ฅผ Object(JavaScript Object)์ฒ๋ผ ์กฐ์(Manipulation)ํ ์ ์๋ Model์
๋๋ค. ์ฆ, ์ฌ๋ฌ๋ถ์ด JavaScript๋ฅผ ์ฌ์ฉํ ์ ์์ผ๋ฉด, DOM์ผ๋ก HTML์ ์กฐ์ํ ์ ์์ต๋๋ค.
html
-head
--title
--meta
--link
-body
--header#header
---nav
---div
--main
--footer
---"hello"
--script
๊ฐ์ ๊ตฌ์กฐ๋ก ๋์์ต๋๋ค. ์ฆ ๊ณ์ธต์ ๊ตฌ์กฐ๋ก ๋์ด์๋๋ฐ์. header, main, footer, script์ ๋ถ๋ชจ๋ body์ด๊ณ , head์ body์ ๋ถ๋ชจ๋ html์ด๋ผ๊ณ ํ ์ ์์ต๋๋ค. head์ body๋ ํ์ ์๋งค ๊ด๊ณ์ด๊ฒ ์ฃ . header๋ body์ ์์์ด๊ณ ์. footer์ ์์๋ ํ๊ทธ ๋์ "hello"๋ผ๋ ๋ฌธ์๊ฐ ๋ค์ด์์ต๋๋ค. ์ ์๊ฐ์ ๋ค๋ฃฌ ํ ์คํธ ๋ ธ๋์ฃ .
์ด๊ฑธ ์ ์๊ฐํด๋ณด๋ฉด ๊ฐ์ฒด๋ก ํํํ ์ ์์ต๋๋ค.
{
document: {
html: {
head: {
title: ...
},
body: {
header: ...
}
}
}
}
์ด๋ ๊ฒ ๋ค์ด๊ฐ ์ ์์ต๋๋ค. ์์ ๊ฐ์ด ๋ง๋ ๊ฒ DOM์ ๋๋ค. ์ ๋ง ๊ฐ์ฒด ๋ชจ์์ผ๋ก ํํ๋์ฃ ? ๊ฐ์ฅ ์๋ document๊ณ ์. ์์์ผ๋ก ๊ฐ ๋๋ html ํ๊ทธ๋ฅผ ๊ฑด๋ ๋ฐ๊ณ , head์ body๋ก ๊ฐ๋๋ค. head์ body๋ ๊ฐ๊ฐ document.head, document.body๋ก ์ ๊ทผํ ์ ์์ต๋๋ค.
[Node์ Element] https://velog.io/@dding/node-elemnet
์น ๋ธ๋ผ์ฐ์ ๊ฐ ์์ฑ๋ ์ฝ๋๋ฅผ ํด์ํ๋ ๊ณผ์ ์์ <script>
์์๋ฅผ ๋ง๋๋ฉด, ์น ๋ธ๋ผ์ฐ์ ๋ HTML ํด์์ ์ ์ ๋ฉ์ถฅ๋๋ค. HTML ํด์์ ์ ์ ๋ฉ์ถ ์น ๋ธ๋ผ์ฐ์ ๋ <script>
์์๋ฅผ ๋จผ์ ์คํํฉ๋๋ค.
์คํฌ๋ฆฝํธ ์์น
https://velog.io/@dding/html-script
<html>
<body>
<div id="nav">
<div class="logo"></div>
<div class="menu-wrapper">
<div class="menu"></div>
<div class="menu"></div>
<div class="menu"></div>
<div class="profile-photo"></div>
</div>
</div>
<div id="news-contents">
<div class="news-content-wrapper">
<div class="news-picture"></div>
<div class="news-title"></div>
<div class="news-description"></div>
</div>
</div>
<div id="footer"></div>
</body>
</html>
body ์์์ ์์ ์์๋ ์ด 3๊ฐ์ ๋๋ค. id๊ฐ nav, news-contents, footer ์ธ 3๊ฐ์ง ์์์ ๋๋ค.
์๋ฐ์คํฌ๋ฆฝํธ์์ DOM์ document ๊ฐ์ฒด์ ๊ตฌํ๋์ด ์์ต๋๋ค. ๋ธ๋ผ์ฐ์ ์์ ์๋๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋์์๋, ์ด๋์์๋ document ๊ฐ์ฒด๋ฅผ ์กฐํํ ์ ์์ต๋๋ค. ํ๋ฒ, body๋ฅผ ์ฐพ์๋ณด๊ฒ ์ต๋๋ค.
DOM ๊ตฌ์กฐ๋ฅผ ์กฐํํ ๋์๋ console.dir ์ด ์ ์ฉํฉ๋๋ค. console.dir ์ console.log ์ ๋ฌ๋ฆฌ DOM์ ๊ฐ์ฒด์ ๋ชจ์ต์ผ๋ก ์ถ๋ ฅํฉ๋๋ค.
console.dir(document.body)
๋ฅผ ํตํด ์ถ๋ ฅ๋ ๊ฐ์ฒด์์, children ์์ฑ์ ์ฐพ์ ์ ์์ต๋๋ค. children ์์ฑ์ nav, news-contents, footer ๊ฐ ์์์ผ๋ก ์๋ ๊ฒ์ ํ์ธํ ์ ์์ต๋๋ค. ๋ฌผ๋ก document.body.children
์ผ๋ก ๋ฐ๋ก ์กฐํํ ์๋ ์์ต๋๋ค.
<html>
<body>
<div id="nav">
<div class="logo"></div>
<div class="menu-wrapper">
<div class="menu"></div>
<div class="menu"></div>
<div class="menu"></div>
<div class="profile-photo"></div>
</div>
</div>
<div id="news-contents">
<div class="news-content-wrapper">
<div class="news-picture"></div>
<div class="news-title"></div>
<div class="news-description"></div>
</div>
</div>
<div id="footer"></div>
</body>
</html>
id๊ฐ news-contents ์ธ div ์์๋ <body>
์์์ ์์ ์์์
๋๋ค. ๋ฐ๋๋ก <body>
์์๋ id๊ฐ news-contents div ์์์ ๋ถ๋ชจ ์์์
๋๋ค. ์ด ๊ด๊ณ๋ฅผ ์๋ฐ์คํฌ๋ฆฝํธ์์ ํ์ธํฉ๋๋ค. id๊ฐ news-contents ์ธ ์๋ฆฌ๋จผํธ๋ฅผ ์กฐํํ๋ ค๋ฉด, document.body.children
์ ์ฒซ ๋ฒ์งธ ์์๋ฅผ ์กฐํํฉ๋๋ค.
document.body.children[1]
div#news=contents
accessKey: ""
...
document.body ์ children์ ์กฐํํ ๋๋ง๋ค, ๋งค๋ฒ document.body ๋ก๋ถํฐ ์ฐพ์๊ฐ๋ ์ผ์ ์ ๋ง ๋ฒ๊ฑฐ๋กญ์ต๋๋ค. ๋ฐ๋ก ๋ณ์ ์ ์ธ์ ํด์ ์ด ์ ๋ณด๋ฅผ ์ ์ฅํด๋๋ฉด, ์ฃผ์๋ฅผ ์ฐธ์กฐํ๊ธฐ ๋๋ฌธ์ ์ธ์ ๋ ์ง ์ ๊ทผํ ์ ์์ต๋๋ค. ๋ณ์ newsContents ๋ฅผ ๋ฐ๋ก ์ ์ธํ์ฌ id๊ฐ news-contents ์ธ ์์๋ฅผ ํ ๋นํฉ๋๋ค.
let newsContents = document.body.children[1]
console.log(newsContents)
div#news=contents
accessKey: ""
document ๊ฐ์ฒด์ createElement ๋ฉ์๋๋ฅผ ์ด์ฉํ์ฌ<div>
์์๋ฅผ ๋ง๋ญ๋๋ค.
document.createElement('div')
// ์๋กญ๊ฒ ์์ฑํ div element๋ฅผ ๋ณ์์ ํ ๋นํฉ๋๋ค.
const tweetDiv = document.createElement('div')
create๋ง ํ ์์๋ ํ์ฌ ๊ณต์ค๋ถ์ ์ค์ด๋ค. ์๋ฌด๊ฒ๋ ์ฐ๊ฒฐ๋์ด ์์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
// ๋ณ์ tweetDiv์ ๋ด๊ธด ์๋ก์ด <div> ์์๋ฅผ <body> ์์์ append ํฉ๋๋ค.
document.body.append(tweetDiv)
ํ๋ฉด์์ผ๋ก ์๋ฌด๊ฒ๋ ๋ณด์ด์ง ์๋ ๊ฒ ์ ์์ด๋ค. ๊ฐ๋ฐ์ ๋๊ตฌ Elements ํญ์์ ํ์ธ ๊ฐ๋ฅํ๋ค.
DOM์ผ๋ก HTML ์๋ฆฌ๋จผํธ์ ์ ๋ณด๋ฅผ ์กฐํํ๊ธฐ ์ํด์๋ querySelector์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ์ ๋ ํฐ(selector)๋ฅผ ์ ๋ฌํ์ฌ ํ์ธํ ์ ์์ต๋๋ค. ์ ๋ ํฐ๋ก๋ HTML ์์("div"), id("#tweetList"), class(.tweet) ์ธ ๊ฐ์ง๊ฐ ๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ๋ฉ๋๋ค.
์ฐธ๊ณ ๋ก querySelector๋ ์ ๋ ํฐ๋ฅผ ์กฐํํ๋ค๋ ์๋ฏธ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. query์ ์๋ฏธ๊ฐ "์ง๋ฌธํ๋ค"๋ผ๋ ๊ฒ์ ์๊ณ ์๋ค๋ฉด ์ญํ ์ ์ฝ๊ฒ ์ ์ถํ์ค ์ ์์ต๋๋ค. ์ด query๋ผ๋ ๋จ์ด๋ ๊ฐ๋ฐ์ ๊ฐ์ "ใ ใ ใ ๋ฅผ ์กฐํํ๋ค"๋ผ๋ ์๋ฏธ๋ฅผ "์ฟผ๋ฆฌ๋ฅผ ๋ ๋ฆฌ๋ค"๋ผ๋ jargon(ํน์ ์์ญ์์๋ง ์ฌ์ฉ๋๋ ๋จ์ด)๋ก ๊ตณ์ด์ก๊ธฐ ๋๋ฌธ์ ์๊ณ ์์ด์ผ ํฉ๋๋ค.
querySelector ์ '.tweet' ์ ์ฒซ ๋ฒ์งธ ์ธ์๋ก ๋ฃ์ผ๋ฉด, ํด๋์ค ์ด๋ฆ์ด tweet ์ธ HTML ์๋ฆฌ๋จผํธ ์ค ์ฒซ ๋ฒ์งธ ์๋ฆฌ๋จผํธ๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
const oneTweet = document.querySelector('.tweet')
์ฌ๋ฌ ๊ฐ์ ์์๋ฅผ ํ ๋ฒ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด์๋, querySelectorAll ์ ์ฌ์ฉํฉ๋๋ค.
const tweets = document.querySelectorAll('.tweet')
CREATE์์ ์์ฑํ div ์์๋ฅผ container์ ๋ฃ์ ์ค๋น๋ฅผ ๋ง์ณค์ต๋๋ค. ๋ค์ ์ฝ๋๋ฅผ ์ ๋ ฅํ๋ฉด, container์ ๋งจ ๋ง์ง๋ง ์์ ์์๋ก tweetDiv๋ฅผ ์ถ๊ฐํฉ๋๋ค.
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
// ๋น div ํ๊ทธ๋ฅผ ์
๋ฐ์ดํธ ํ๋ค
const oneDiv = document.createElement('div');
console.log(oneDiv) // <div></div>
๋น div ํ๊ทธ๋ฅผ ์ ๋ฐ์ดํธํ์ฌ, ๋ณด๋ค ๋ค์ํ ์์ ์ ํ ์ ์์ต๋๋ค. ๋จผ์ , textContent ๋ฅผ ์ฌ์ฉํด์, ๋น์ด์๋ div ์๋ฆฌ๋จผํธ์ ๋ฌธ์์ด์ ์ ๋ ฅํฉ๋๋ค.
CSS ์คํ์ผ๋ง์ด ์ ์ฉ๋ ์ ์๋๋ก, div ์๋ฆฌ๋จผํธ์ class๋ฅผ ์ถ๊ฐํฉ๋๋ค.
oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class="tweet">dev</div>
์์ฑํ ์๋ฆฌ๋จผํธ์ ํ ์คํธ๋ฅผ ์ฑ์ ๊ณ , ํด๋์ค๋ฅผ ์ถ๊ฐํ์ฌ ์คํ์ผ๋ง์ ์ ์ฉํ์ต๋๋ค. ์ด๋ฒ์๋ append๋ฅผ ์ด์ฉํด container์ ์์ ์์๋ก ์ถ๊ฐํฉ๋๋ค.
const container = document.querySelector('#container')
container.append(oneDiv)
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // ์ด๋ ๊ฒ append ํ๋ ์์๋ฅผ ์ญ์ ํ ์ ์๋ค.
innerHTML ์ ์ด์ฉํ๋ฉด, ์์ฃผ ๊ฐ๋จํ๊ฒ ๋ชจ๋ ์์ ์์๋ฅผ ์ง์ธ ์ ์์ต๋๋ค. ์ปจํ ์ด๋์ ๋ชจ๋ ์์ ์์๋ฅผ ์ง์ฐ๋ ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ด ์ ๋ ฅํฉ๋๋ค.
document.querySelector('#container').innerHTML = '';
innerHTML ์ ์ด์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ถ๋ช ๊ฐํธํ๊ณ ํธ๋ฆฌํ ๋ฐฉ์์ด์ง๋ง, innerHTML์ ๋ณด์์์ ๋ช ๊ฐ์ง ๋ฌธ์ ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. ์ด ๋ฐฉ๋ฒ์ ๋์ ํ ๋ค๋ฅธ ๋ฉ์๋๋ฅผ ์ฌ์ฉํฉ๋๋ค. removeChild ๋ ์์ ์์๋ฅผ ์ง์ ํด์ ์ญ์ ํ๋ ๋ฉ์๋์ ๋๋ค. ๋ชจ๋ ์์ ์์๋ฅผ ์ญ์ ํ๊ธฐ ์ํด, ๋ฐ๋ณต๋ฌธ(while, for, etc.)์ ํ์ฉํ ์ ์์ต๋๋ค. ๋ค์์ ์ฝ๋๋ ์์ ์์๊ฐ ๋จ์์์ง ์์ ๋๊น์ง, ์ฒซ ๋ฒ์งธ ์์ ์์๋ฅผ ์ญ์ ํ๋ ์ฝ๋์ ๋๋ค.
const container = document.querySelector('#container');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// container์ ์ฒซ ๋ฒ์งธ ์์ ์์๊ฐ ์กด์ฌํ๋ฉด, ์ฒซ ๋ฒ์งธ ์์ ์์๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
removeChild ์ while ์ ์ด์ฉํด ์์ ์์๋ฅผ ์ญ์ ํ๋ฉด, ์ ๋ชฉ์ ํด๋นํ๋ H2 "Tweet List"๊น์ง ์ญ์ ๋ฉ๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๊ฐ์ง๊ฐ ์์ต๋๋ค. ์์ ์์๊ฐ ๋ด๊ณ ์๋ ๋ฌธ์์ด์ ๋น๊ตํด "Tweet List"๋ง ๋จ๊ธฐ๊ฑฐ๋, ์๋ก์ด ๋ณ์๋ฅผ ์์ฑํ๊ณ Tweet List๋ฅผ ํ ๋นํด๋๋ค๊ฐ ๋ฐ๋ณต๋ฌธ์ด ๋๋ ๋ค์ ์๋กญ๊ฒ ์ถ๊ฐํ ์๋ ์์ต๋๋ค. ๋๋ ์์ ์์๋ฅผ ํ๋๋ง ๋จ๊ธฐ๊ฒ ํ ์๋ ์์ต๋๋ค.
// container์ ์์ ์์๊ฐ 1๊ฐ๋ง ๋จ์ ๋๊น์ง, ๋ง์ง๋ง ์์ ์์๋ฅผ ์ ๊ฑฐํฉ๋๋ค.
const container = document.querySelector('#container');
while (container.children.length > 1) {
container.removeChild(container.lastChild);
}
๋๋ ์ง์ ํด๋์ค ์ด๋ฆ์ด tweet์ธ ์์๋ง ์ฐพ์์ ์ง์ฐ๋ ๋ฐฉ๋ฒ๋ ์์ต๋๋ค.
const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
tweet.remove();
})
// or
for (let tweet of tweets){
tweet.remove()
}