DOM

왕지호·2022년 11월 10일
0
post-custom-banner

오늘은 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>요소를 추가하는 두 가지 대표적인 사례,

  1. <head> 요소에 추가하기
  2. </body>가 끝나기 전에 추가하기

두 방식의 공통점과 차이점

  • 두 방식 모두 myScriptFile.js 내의 첫 번째 console.log를 성공적으로 출력하지만, 두 번째 console.log의 경우 제대로 출력하지 못하는 예시가 있다.
console.log('welcome JavaScript');

let msgElement = document.querySelector('#msg');
console.log(msgElement);

head의 경우

  • 브라우저 렌더링에 방해가 되어 무거운 스크립트가 실행되는 경우 오랫동안 완성되지 못한 화면을 노출하게 된다.
  • 문서를 초기화하거나 설정하는 가벼운 스크립트들이 자주 사용된다.
  • 문서의 DOM(Document Object Model) 구조가 필요한 스크립트의 경우 document.onload와 같은 로드 이벤트가 추가되어야 에러없이 작동된다.

body의 경우

  • 브라우저가 렌더링이 완료된 상태에서 스크립트가 실행되기에 콘텐츠를 변경하는 스크립트의 경우 화면에 노출된체로 변화된다.
  • 대부분의 스크립트의 위치로 추천되는 위치이다.
  • 문서의 DOM 구조가 완료된 시점에 실행되기에 별다른 추가설정이 필요없다.

자식요소 찾기

  • DOM 구조를 조회할 때에는 console.dir이 유용하다

  • console.dirconsole.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를 추가해보자!

CREATE

  • document 객체의 createElement 메서드를 이용하여 <div>요소를 만들어보자
document.createElement('div')

자바스크립트에서 어떤 작업의 결과를 담으려면 어떻게 해야 할까? 변수를 선언하고 어떤 작업의 결과를 변수에 할당해야 한다. 여기서는 div element를 변수 tweetDiv 에 할당한다.

const tweetDiv = document.createElement('div')

하지만 지금은 만들어도 화면에 아무 변화가 일어나지 않는다.
그렇기 때문에 엘리먼트를 확인하려면 APPEND가 필요하다.

APPEND

그럼 이제 HTML Element를 부모 노드에 포함해보자

  • append 라는 메서드를 사용해서, 변수 tweetDiv<body> 에 넣어보자
document.body.append(tweetDiv)

READ

다음으로 HTML Element를 조회 해보자!

  • 자바스크립트에서 원시 자료형인 변수의 값을 조회하기 위해서는, 변수의 이름으로 직접 조회할 수 있다.
  • DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있다.
  • 셀렉터로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용된다.
  • querySelector는 셀렉터를 조회한다는 의미를 가지고 있다!

querySelector

  • querySelector'.tweet' 을 첫 번째 인자로 넣으면, 클래스 이름이 tweet 인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있다.
const oneTweet = document.querySelector('.tweet')
  • HTML 문서에는 클래스 이름이 tweet 인 요소가 여러 개 있는 데, 변수 oneTweet 에 할당된 요소는 단 하나
  • 여러 개의 요소를 한 번에 가져오기 위해서는, querySelectorAll 을 사용한다
  • 이렇게 조회한 HTML 요소들은 배열처럼 for문을 사용할 수 있다
  • 주의하자! 앞서 조회한 HTML 요소들은 배열이 아니다! 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체 등 다양한 이름으로 부른다. 정식 명칭은 Array-like Object 라고 부른다.
const tweets = document.querySelectorAll('.tweet')

[코드] querySelectorAll로 클래스 이름이 tweet 인 모든 HTML 요소를 유사 배열로 받아온다

  • querySelectorquerySelectorAll 만 알아도 대부분의 요소를 조회할 수 있다.
const getOneTweet = document.getElementById('container')
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true

[코드] getElementById와 querySelector로 각각 받아 온 container 요소는 하나의 요소

  • CREATE에서 생성한 div 요소를 container에 넣을 준비를 마쳤으니, 다음 코드를 입력하면, container의 맨 마지막 자식 요소로 tweetDiv를 추가해보자
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)

UPDATE

이제 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>
  • 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)

DELETE

마지막으로 HTML Element를 삭제해보자

  • CRUD의 Delete, 삭제하는 법!
  • 삭제하는 방법에도 여러 가지가 있다. 먼저 삭제하려는 요소의 위치를 알고 있는 경우에 사용하는 방법이 있다.
  • 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 는 자식 요소를 지정해서 삭제하는 메서드
  • 모든 자식 요소를 삭제하기 위해, 반복문(while, for, etc.)을 활용할 수 있다
  • 다음의 코드는 자식 요소가 남아있지 않을 때까지, 첫 번째 자식 요소를 삭제한다
const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
}
  • removeChildwhile 을 이용해 자식 요소를 삭제하면, 제목에 해당하는 H2 "Tweet List"까지 삭제된다
  • 이를 방지하기 위한 방법은 여러 가지가 있는데, 자식 요소가 담고 있는 문자열을 비교해 "Tweet List"만 남기거나, 새로운 변수를 생성하고 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()
}
profile
개발 공부하는 코린이!
post-custom-banner

0개의 댓글