오늘은 DOM에 대해서 알아보자!
- 트리 구조인 DOM
트리 구조의 가장 큰 특징은 부모가 자식을 여러 개 가지고, 부모가 하나인 구조가 반복되는 점이다. 즉, 부모가 가진 하나 또는 여러 개의 자식 엘리먼트를 조회하는 코드를 작성한다면, 여러 번 반복해서 실행하는 코드가 필요하다.
DOM
- Document Object Model
- HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model
- JavaScript를 사용할 수 있으면, DOM으로 HTML을 조작할 수 있음
- HTML을 분석하여 HTML의 아주 작은 부분까지 접근할 수 있는 구조
- DOM을 이용하면 HTML로 구성된 웹 페이지를 동적으로 움직이게 만들 수 있다
- 조건문과 반복문, 배열, 객체를 활용하면 소셜 미디어에서 새롭게 생성되는 게시물을 저장하고 분류하는 작업을 구현할 수 있다
HTML에 Javascript를 적용하기 위해서는<script>
태그를 이용한다.
아래의 경우 HTML 파일과 같은 디렉토리에 존재하는 myScriptFile.js
을 불러온다!
<script src="myScriptFile.js"></script>
웹 브라우저가 작성된 코드를 해석하는 과정에서 <script>
요소를 만나면, 웹 브라우저는 HTML 해석을 잠시 멈춘다
HTML 해석을 잠시 멈춘 웹 브라우저는 <script>
요소를 먼저 실행한다
<script>
요소는 등장과 함께 실행된다는 사실을 꼭 기억하자!
<script>
요소를 추가하는 두 가지 대표적인 사례,<head>
요소에 추가하기</body>
가 끝나기 전에 추가하기console.log('welcome JavaScript');
let msgElement = document.querySelector('#msg');
console.log(msgElement);
head의 경우
document.onload
와 같은 로드 이벤트가 추가되어야 에러없이 작동된다.body의 경우
DOM 구조를 조회할 때에는 console.dir
이 유용하다
console.dir
은 console.log
와 달리 DOM을 객체의 모습으로 출력
console.dir은 너무 많은 속성이 나타나기 때문에, 그래서 자식 요소를 검색하고 싶을 때 document.body.children 사용한다
id가 news-contents
인 div 요소는 <body>
요소의 자식 요소이다. 반대로 <body>
요소는 id가 news-contents
div 요소의 부모 요소이다.
id가 news-contents
인 엘리먼트를 조회하려면, document.body.children
의 첫 번째 요소를 조회한다.
document.body
의 children을 조회할 때마다, 매번 document.body
로부터 찾아가는 일은 정말 번거롭기 때문에 따로 변수 선언을 해서 이 정보를 저장해두면, 주소를 참조하기 때문에 언제든지 접근할 수 있다.
그럼 이제 DOM을 이용하여 HTML Element를 추가해보자!
<div>
요소를 만들어보자document.createElement('div')
자바스크립트에서 어떤 작업의 결과를 담으려면 어떻게 해야 할까? 변수를 선언하고 어떤 작업의 결과를 변수에 할당해야 한다. 여기서는 div
element를 변수 tweetDiv
에 할당한다.
const tweetDiv = document.createElement('div')
하지만 지금은 만들어도 화면에 아무 변화가 일어나지 않는다.
그렇기 때문에 엘리먼트를 확인하려면 APPEND가 필요하다.
그럼 이제 HTML Element를 부모 노드에 포함해보자
append
라는 메서드를 사용해서, 변수 tweetDiv
를 <body>
에 넣어보자document.body.append(tweetDiv)
다음으로 HTML Element를 조회 해보자!
querySelector
의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있다."div"
), id("#tweetList"
), class(.tweet
) 세 가지가 가장 많이 사용된다.querySelector
에 '.tweet'
을 첫 번째 인자로 넣으면, 클래스 이름이 tweet
인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있다.const oneTweet = document.querySelector('.tweet')
oneTweet
에 할당된 요소는 단 하나querySelectorAll
을 사용한다const tweets = document.querySelectorAll('.tweet')
[코드] querySelectorAll로 클래스 이름이 tweet 인 모든 HTML 요소를 유사 배열로 받아온다
querySelector
와 querySelectorAll
만 알아도 대부분의 요소를 조회할 수 있다.const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true
[코드] getElementById와 querySelector로 각각 받아 온 container 요소는 하나의 요소
container
의 맨 마지막 자식 요소로 tweetDiv
를 추가해보자const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
이제 HTML Element를 변경하는 방법을 실습해보자
oneDiv
라는 이름의 <div>
요소를 만들어 보자const oneDiv = document.createElement('div');
console.log(oneDiv) // <div></div>
기존에 생성한 빈 div 태그를 업데이트하여, 보다 다양한 작업을 할 수 있다
먼저, textContent
를 사용해서, 비어있는 div 엘리먼트에 문자열을 입력하자
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>
class
를 추가oneDiv.classList.add('tweet')
console.log(oneDiv) // <div class="tweet">dev</div>
const container = document.querySelector('#container')
container.append(oneDiv)
마지막으로 HTML Element를 삭제해보자
remove
메서드를 사용해서 앞서 생성하고 추가한 tweetDiv
를 삭제해보자const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.
[코드] id가 container인 요소 아래에 tweetDiv를 추가하고, remove로 삭제
그렇다면, 여러 개의 자식 요소를 지우려면, 어떻게 해야 할까?
innerHTML
을 이용하면, 아주 간단하게 모든 자식 요소를 지울 수 있다document.querySelector('#container').innerHTML = '';
[코드] id가 container인 요소 아래의 모든 요소를 지움
innerHTML
을 이용하는 방법은 분명 간편하고 편리한 방식이지만, innerHTML은 보안에서 몇 가지 문제를 가지고 있다.
removeChild
는 자식 요소를 지정해서 삭제하는 메서드const container = document.querySelector('#container');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
removeChild
와 while
을 이용해 자식 요소를 삭제하면, 제목에 해당하는 H2 "Tweet List"까지 삭제된다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()
}