DOM
은 Document Object Model
의 약자로, HTML 요소를 Object(JavaScript Object)처럼 조작(Manupulation)할 수 있는 Model입니다.
즉, JS를 사용 할 수 있으면, DOM으로 HTML을 조작할 수 있습니다.
HTML을 조작할 수 있다는 것이 무슨 뜻일까? 여러 뛰어난 웹 개발자들이 모여 HTML을 분석하여 HTML의 아주 작은 부분까지 접근 할 수 있는 구조를 만들었다. 이렇게 만들어진 구조를 DOM이라고 한다. DOM을 이욜하면 GTML로 구성된 웹 페이지를 동적으로 움직이게 만들 수 있다. ㅇ앞서 학습한 조건문과 반복문, 배열, 객체를 활용하면 소셜 미디어에서 새롭게 생성되는 게시물을 저장하고 분류하는 작업을 구현 할 수 있다.
웹 브라우저가 작성된 코드를 해석하는 과정에서 <script>
요소를 만나면, 웹 브라우저는 HTML 해석을 잠시 멈춘다. HTML해석을 잠시 멈춘 웹 브라우저는 <script>
요소를 먼저 실행한다. <script>
요소는 등장과 함께 실행된다는 사실을 꼭 기억하자.
<script>
요소를 추가하는 두 가지 대표적인 사례가 존재한다. 하나는 <head>
요소에 추가하는 방법, 다른 하나는 <body>
가 끝나기 전에 추가하는 방법.
+@) 일반적으로 CSS를 불러오기 위해
<link>
요소를<head>
요소의 자식 요소로 하고, JavaScript를 불러오기 위해<script>
요소를<body>
요소가 끝나기 직전에 위치시키는 이유가 무엇인가요?답변 = 각 요소의 위치는 html 의 렌더링에 방해되는 요소를 최대한 방지하기 위한 최적의 자리에 지정하고 있습니다. HTML이 로드되면 한 줄 씩 실행됩니다.
<head>
태그에 CSS link를 배치하면 페이지가 동시에 렌더링되고 스타일이 지정됩니다. 만일 css link가 하단에 있을 경우 html 렌더링이 된 다음 css 스타일이 적용되어 페이지가 두번 렌더링 됩니다. 첫 번째 렌더링에서는 최소한의 HTML만 로드 되고 렌더링 됩니다. 두 번째 렌더링에서는 스타일이 적용되고 페이지가 다시 렌더링됩니다. 이로인해 HTML요소의 크기, 모양, 색상이 변경되고 웹 페이지가 깜빡일 수 있습니다. 그렇기 때문에<body>
태그가 아닌<head>
태그 안에 배치해야 합니다. 또한 자바스크립트 코드는 html 태그 어디에 있더라도 동작하지만, 매우 무거운 자바스크립트 코드가 포함되어 있는 경우 그 코드들을 불러오고 실행하느라, 그 밑에 있는 html 코드들이 로딩되지 못하게 될 것입니다. 이는 브라우자가 렌더링 되는 것에 방해가 될 수 있습니다. 그래서 사용자는 완성되지 않은 중간 화면을 오랫동안 쳐다보고 있어야 할지도 모릅니다. 따라서 css link는 head에 script 요소는 body 마지막에 위치시키는 것이 바람직합니다.
document
객체에는 많은 속성과 메서드가 존재한다. 따라서 지금 집중할 부분은 CRUD
Create, Read, Update, Delete 이다.
document.createElement('div')
//<div></div> 요소를 만든다.
새롭게 생성한 div elemnet 는 어떻게 활용할 수 있는가?
자바스크립트에서 어떤 작업의결과를 담으려면 어떻게 해야할까?
변수를 선언하고 어떤 작업의 결과를 변수에 할당해야 한다.
ㅇ기서는 div
element를 변수 tweeetDiv
에 할당한다.
const tweetDiv document.createElement('div')
tweetDiv 라는 요소는 현재 공중부양 중.
아무것도 연결이 되어있지 않은 하나의 노드.
공중에 떠있는 엘리먼트를 확인하기 위해서는 APPEND 해야한다. APPEND를 이용해 실제 웹 페이지 상에도 보이는 것을 확인 할 수 있다.
append
라는 메서드를 사용해서, 변수 tweetDiv
를 <body>
에 넣어보자.
documnet.body.append(tweetDiv)
새롭게 생성한<div>
요소에 아무런 내용을 입력하지 않아서 보이는 내용이 없을 뿐 존재한다.
자바스크립트에서 원시 자료형인 변수의 값을 조회하기 위해서는, 변수의 이름으로 직접 조회할 수 있다. 잠조 자료형인 배열은 index를, 객체는 key를 이용해 값을 조회할 수 있다. 그러나 DOM은 조금 특별한 방법을 사용해야 한다. DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector
의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인 할 수 있다. 셀렉터로는 HTML요소 ("div"
),id("#tweetList"
),class(.tweet
)세 가지가 가장 많이 사용된다.
참고로 queryselector는 셀렉터를 조회한다는 의미를 가지고 있다. query의 의미가 "질문하다" 라는 것을 알고 있다면 역할을 쉽게 유추할 수 있다. 이 quey라는 단어는 개발자 간에 "ㅇㅇㅇ을 조회한다:라는 의미를 '쿼리를 날리다" 라는 jargon(특정 영역에서만 사용되는 단어)로 굳어졌기 때문에 알고 있어야 한다.
querySelector
에 '.tweet'
을 첫 번째 인자로 넣으면, 클래스 이름이 tweet
인 HTML엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있다.
const oneTweet = documnet.querySelector('.tweet')
HTML 문서에는 클래스 이름이 tweet인 요소가 여러 개 있는데, 변수 oneTweet
에 할당된 요소는 단 하나이다.
여러개의 요소를 한번에 가져오기 위해서는, queryselectorAll
을 사용해야 한다. 이렇게 조회한 HTML요소들은 배열처럼 for문을 사용할 수 있다.
앞서 ㅈ회한 HTML요소들은 배열이 아니다. 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체등 다양한 이름으로 부른다. 정식 명칭은 Array-like Object
이다.
위와 같이 개념을 설명하는 용어는 영어로도 명확하게 기억해두는 게 좋다.
const tweets = document.querySelectorAll('tweet')
querySelector
와 querySelectorAll
만 알아도 대부분의 요소를 조회할 수 있다. 다만, 아래와 같이 get
으로 시작하는 DOM 조회 메서드를 볼 수도 있다. 이런 메서드는 querySelector
와 비슷한 역할을 하는 오래된 방식이라고만 이해하면 된다. 만약 이전 버전의 브라우저 호환성을 신경 써야한다면, 이런 예산 ㄹ방싱을 사용해야 할 수도 있다.
실제 동작은 동일하니 이런 메서드가 있다는 것 정도는 알아두자.
const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) //true
CREATE에서 생성한 div요소를 container에 넣은 준비를 마쳤다. 다음 코드를 입력하면, container
의 맨 마지막 자식 요소로 tweetDiv
를 추가한다.
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
새롭게 추가된 tweetDiv
는 별도의 class
가 지정되어 있지 않아, CSS를 이용한 스타일링이 적용되지 않는다. 새롭게 생성한 tweetDiv
에 calss
를 붙여 스타일링을 적용하자.
oneDiv
라는 이름의 <div>
요소를 만들어 보자
const oneDiv = document.createElement('div');
console.log(oneDiv) // <div></div>
기존에 생성한 빈 div태그를 업데이트하여, 보다 다양한 작업을 할 수 있다. 먼저, textcontent
를 사용해서, 비어있는 div 엘리먼트에 문자열을 입력한다.
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>
앞서 생성한 div 엘리먼트를 container에 append 했을 때, CSS 스타일링이 적용되지 않았다. 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)
새롭게 추가한 엘리먼트는 클래스 tweet
의 스타일이 적용된 상태로 출력된다.
삭제하는 방법에도 여러 가지가 있다. 먼저 삭제하려는 요소의 위치를 알고 있는 경우에 사용하는 방법.
앞서 생성하고 추가한 tweetDiv
를 삭제한다. remove
메서드를 사용하자
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.
여러 개의 자식 요소를 지우려면, 어떻게 해야 할까? innerHTML
을 이용하면, 간단하게 모든 자식 요소를 지울 수 있다. 컨테이너의 모든 자식 요소를 지우려면, 다음과 같이 입력하자.
document.querySelector('#container').innerHTML = '';
innerHTML
을 이용하는 방법은 간편하고 편리한 방식이지만 보안에서 몇 가지 문제를 가지고 있다. 이 방법을 대신할 다른 메서드를 사용하자. removeChild
는 자식 요소를 지정해서 삭제하는 메서드이다. 모든 자식 요소를 삭제하기 위해, 반복문을 활용할 수 있다. 다음의 코드는 자식 요소가 남있지 않을 때까지, 첫 번째 자식 요소를 삭제하는 코드
const container = document.querySelector('#container');
while (container.firstChild) {
container.removeChild(container.firstChild);
}
removeChild
와 whil
을 이용해 자식 요소를 삭제하면, 제목에 해당하는 H2 "Tweet List"까지 삭제된다. 이를 방지하기 위한 방법은 여러 라지가 있다. 자식 요소가 담고 있는 문자열을 비교해 "Tweet List"만 남기거나, 새로운 변수를 생성하고 Tweet List를 할당해뒀다가 반복문이 끝난 뒤에 새롭게 추가할 수도 있다. 또는 자식 요소를 하나만 남기게 할 수도 있다.
const container = document.querySelector('#container');
while (container.children.length > 1) {
container.removeChild(container.lastChild);
}
//container의 자식 요소가 1개만 남을 때까지, 마지막 자식 요소를 제거한다.
또는 직접 클래스 이름이 tweet인 요소만 찾아서 지우는 방법도 있다.
const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
tweet.remove();
})
// or
for (let tweet of tweets){
tweet.remove()
}
Dom(Document Object Model) + Bom(Browser Object Model) = Web Api
Head script vs body script
HTML 다운 받기를 멈추고(렌더링 멈춤) JS 를 다운로드 후 다시 HTML 을 다운 받기 시작함
head에 넣을 경우
Async 속성 설정
Defer 속성 설정 - 자바스크립트를 다운로드 받자마자 HTML 다운로드 받기 때문에 속도가 빠를 수 있다.
(서비스가 크지 않다면 무의미 하다. )
(추후 작성 예정)