코드스테이츠 - 유어클래스 콘텐츠를 참고하여 작성하였습니다.
[Day 6]
2023년 7월 3일
📗목차
DOM은 Document Object Model의 약자로, HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model이다.
즉, JavaScript를 사용할 수 있으면, DOM을 이용하여 HTML을 조작할 수 있고, HTML로 구성된 웹 페이지를 동적으로 움직이게 만들 수 있다.
웹 브라우저가 작성된 코드를 해석하는 과정에서 <script> 요소를 만나면, 웹 브라우저는 HTML 해석을 잠시 멈추고 <script> 요소를 먼저 실행한다.
<script> 요소는 등장과 함께 실행된다는 것을 꼭 기억하기.
HTML에 JavaScript를 적용하기 위해서는 아래와 같이 <script> 태그를 이용한다.
<script src="myScriptFile.js"></script>
이 <script> 요소를 추가하는 두 가지 대표적인 사례가 있다.
<head> 요소에 추가하는 방법
JavaScript를 먼저 실행하기 때문에 HTML에서 id가 msg인 div 요소를 읽지 못 하여 null로 출력된다.
</body> 가 끝나기 전에 추가하는 방법
HTML의 요소들을 먼저 읽고 나서 JavaScript를 실행하여 콘솔에 제대로 출력된다.
Tweet List 프로젝트로 실습을 해보자.
https://github.com/codestates-seb/fe-dom-practice
document.createElement('div')
새로운 <div> 요소를 만든다.
다음 아래와 같이 변수 tweetDiv에 div element를 담는다.
const tweetDiv = document.createElement('div')
위의 CREATE에서 생성한 tweetDiv를 트리 구조와 연결해보자.
const tweetDiv = document.createElement('div')
document.body.append(tweetDiv)
변수 tweetDiv에 담긴 새로운 <div> 요소를 <body> 요소에 append 한다.

JavaScript에서 원시 자료형인 변수의 값을 조회하기 위해서는, 변수의 이름으로 직접 조회할 수 있다. 참조 자료형인 배열은 index를, 객체는 key를 이용해 값을 조회 가능하다. 그러나 DOM은 조금 특별한 방법을 사용해야 하는데, DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 선택자(selector)를 전달하여 확인할 수 있다. 선택자로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용한다.
querySelector에 '.tweet'을 첫 번째 인자로 넣으면, 클래스 이름이 tweet 인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있다.
const oneTweet = document.querySelector('.tweet')
HTML 문서에는 클래스 이름이 tweet 인 요소가 여러 개가 있다고 하자.
변수 oneTweet에 할당된 요소는 단 하나이다. 여러 개의 요소를 한 번에 가져오기 위해서는 어떻게 해야될까?
const tweets = document.querySelectorAll('.tweet')
이럴 땐 querySelectorAll을 사용한다. 이렇게 조회한 HTML 요소들은 배열처럼 for문을 사용할 수 있다.
하지만, 앞서 조회한 HTML 요소들은 배열이 아니다! 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체 등 다양한 이름으로 부르고, 정식 명칭은 Array-like Object이다.
querySelector와 비슷한 역할을 하는 오래된 방식이라고만 이해하면 된다.
만약 이전 버전의 브라우저(인터넷 익스플로러) 호환성을 신경 써야 한다면, 이런 옛날 방식을 사용해야 할 수도 있다.
//getElementById
const getIdTweet = document.getElementById('container')
const queryIdTweet = document.querySelector('#container')
console.log(getIdTweet === queryIdTweet) // true
//getElementByClassName
const getClassTweet = document.getElementByClassName('container')
const queryClassTweet = document.querySelector('.container')
console.log(getClassTweet === queryClassTweet) // true
div 요소를 생성하여 변수 oneDiv에 담고, textContent를 사용해서 비어있는 div 엘리먼트에 문자열을 입력해보자.
const oneDiv = document.createElement('div');
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</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)

삭제하려는 요소의 위치를 알고 있는 경우에 사용하는 방법을 시도해보자.
앞서 생성하고 추가한 tweetDiv를 삭제하려면 remove 메서드를 사용하자.
const container = document.querySelector('#container')
const oneDiv = document.createElement('div')
container.append(oneDiv)
oneDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.
여러 개의 자식 요소를 지우려면, 어떻게 해야 할까? innerHTML을 이용하면, 아주 간단하게 모든 자식 요소를 지울 수 있다. 컨테이너의 모든 자식 요소를 지우려면, 다음과 같이 입력하자.
document.querySelector('#container').innerHTML = '';
innerHTML을 이용하는 방법은 분명 간편하고 편리한 방식이지만, innerHTML은 보안에서 몇 가지 문제를 가지고 있다.
이 방법을 대신할 다른 메서드를 사용한다.
removeChild는 자식 요소를 지정해서 삭제하는 메서드이다. 모든 자식 요소를 삭제하기 위해, 반복문(while, for, etc.)을 활용할 수 있다.
다음 아래는 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()
}

다음 그림은 POS기를 만드는 과정 중 일부이다. 이 두 개의 버튼을 클릭할 때, 각각 "아메리카노를 클릭하셨습니다. 또는 카페라떼를 클릭하셨습니다.라고 출력하는 단순한 프로그램이다.

사용자가 버튼을 클릭하면, 그 버튼의 textContent(또는 innerHTML)을 이용해 메뉴의 이름을 가져올 수 있다.
사용자가 누른 버튼에 따라 출력되는 이름이 달라지므로, 클릭된 이벤트 객체에서 메뉴의 이름을 가져옵니다. 다시 말해, 이벤트 객체는 사용자 입력(onclick, onkeyup, onscroll 등)을 트리거로 발생한 이벤트 정보를 담은 객체입니다.
handleClick 함수를 다음과 같이 변경하고, 다음의 질문에 대한 답을 고민해보자.
event.target.textContent