(JS) DOM : Document Object Model

호두파파·2020년 12월 21일
2

JavaScript

목록 보기
6/25


DOM : Document Object Model

The Document Object Model(DOM)is a programming interface for HTML
요약 설명 : HTML 문서를 위한 프로그래밍 인터페이스

리모콘 버튼을 통해 채널을 변경할 수 있듯이 DOM이라는 인터페이스를 이용한다면, HTML 코드 변경 없이 내용을 변경 추가할 수 있다.

const $text = document.querySelector(".some-text")
$text.textContent = "hello, World";

위 코드는 .some-text라는 클래스(클래스 명은 공백을 하이픈으로 쓰는 케밥 케이스로 작성)를 가진 요소를 선택해 해당 요소의 텍스트를 수정하였습니다. 즉, 자바스크립트를 이용해 HTML 문서를 조종할 수 있다.


HTML 문서와 DOM

엄밀히 말하면, 자바스크립트를 이용해 HTML 문서 자체를 수정하는 것은 아니다.
HTML 문서는 브라우저가 화면을 그리기 위한 초기 설계도의 역할을 한다.

브라우저는 HTML이라는 설계도를 이용해 초기 화면을 그리는 것이고, 우리는 브라우저가 만든 화면을 DOM으로 접근하고 수정 변경하는 것이다.

📌 DOM은 리모컨의 버튼같은 존재라고 이해하면 쉽다.

리모콘의 버튼같은 존재 : Selecting Element

화면 속 요소를 선택하는 방법에는 4가지가 있다.

<div class="container">
  <h1>I am a Heading</h1>
  <p>I am a Paragraph</p>
  <ul>
    <li class="item">
      <p>I am a Paragraph</p>
    </li>
    <li class="item">
      <p>I am a Paragraph</p>
    </li>
    <li class="item">
      <p>I am a Paragraph</p>
    </li>
  </ul>
  <button id="special-button">I am a Button</button>
</div>

1. Document.getElementById : 아이디 이름을 이용하여 선택하기

// special- button 아이디를 가진 요소를 선택해 `$el`변수에 대입 
const $el = document.getElementById("special-button");

// special-button 아이디를 가진 요소의 텍스트 변경 
$el.textContent = "I'm a special Button";

아이디란 기본적으로 하나의 HTML 문서에서 고유한 값이어야 하기 때문에,
위 같이 document.getElementById를 이용하요 요소를 선택할 경우 주어지는 값은 단 하나의 요소이다.

여기서 그 하나의 요소란 Node 혹은 HTML Element라고 부르는 존재이다. (GOOGLE 검색어 : Node vs Element)

2. getElementsByClassName : 클래스 이름을 이용하여 선택하기

// item 클래스를 가진 "모든 요소들"을 선택하여 `$listItems` 변수에 대입 
const $listItems = document.getElementsByClassName("item");

// container 클래스를 가진 "모든 요소들"을 선택하여 `$container`변수에 대입
const $container = document.getElementsByClassName("container")

// getElementByClassName의 결과값은 배열과 유사한 형태이므로 인덱스로 접근해 사용한다.
$listItems[0].textContent = "List 1";
$listItems[1].textContent = "List 2";
$listItems[2].textContent = "List 3";

// HTML 상에서 해당 클래스를 가진 요소가 단 하나 뿐이라도, 
// getElementByClassName의 결과값은 배열과 유사한 형태이므로 인덱스로 접근해 사용한다. 
$container[0].style.backgroundColor = "green";

함수를 이용해 변수에 할당한 존재는 모두 배열과 유사한 형태(유사배열)이다. 이 유사배열에 담긴 배열의 요소들이 하나의 HTML Element이다. 그렇기 때문에 거의 대부분 상황에서 배열의 인덱스 위치를 이용해 사용해야 한다.

3. getElementsByTagName: 태그 이름을 이용하여 선택하기

// li 태그를 이용한 "모든 요소들"을 선택하여 `$listItems` 변수에 대입
const $listItems = document.getElementsByTagName("li");

// p 태그를 이용한 "모든 요소들"을 선택하여 `$paragraphs` 변수에 대입
const $paragraphs = document.getElementsByTagName("p");

// getElementsByTagName의 결과값은 배열과 유사한 형태이므로 인덱스로 접근하여 사용한다.
$listItems[0].textContent = "List 1";
$listItems[1].textContent = "List 2";
$listItems[2].textContent = "List 3";

// 위치와 상관없이 모든 p 태그를 선택하게 되므로 $paragraphs에는 총 4개의 요소가 선택되고,
// 그 중 첫번째 요소의 배경 색깔을 수정합니다.
$paragraphs[0].style.backgroundColor = "green";

4. querySelector : CSS 선택자를 이용하여 선택하는 방법

css 선택자를 이용해 DOM 기능을 활용하는 방법이 최근에 가장 많이 사용되는 방법이다.

// CSS 선택자 문법을 이용해 container라는 클래스 이름을 가진 요소를 선택합니다. 
// querySelector라는 함수는 모든 경우에 "하나의 요소"를 반환한다. 
const $container = document.querySelector(".container");
const $button = document.querySelector("#special-button");
// 주어진 CSS 선택자와 일치하는 요소가 여러 개일 경우,
// querySelector 함수는 가장 첫번째 요소를 반환합니다.
const $listItem = document.querySelector(".item");
// querySelectorAll 함수는 주어진 CSS 선택자와 일치하는 "모든 요소들"을 유사 배열의 형태로 반환합니다.
// (요소를 제어하고 싶다면 인덱스 위치를 사용해야 합니다.)
const $paragraphs = document.querySelectorAll("p");

CRUD: Creat - createElement append appendChild

수정과 삭제가 가능하듯, 우리가 원하는대로 생성할 수도 있다.

// h1 요소 만들어서 `heading`이라는 변수에 할당
const heading = document.createElement("h1");

// 방금 생성한 `heading` 요소의 텍스트 설정
heading.textContent = "제목입니당";
// 방금 생성한 `heading` 요소의 스타일 설정
heading.style.fontSize = "50px";

// 방금 생성한 `heading` 요소를 body 태그의 자식으로 추가
document.body.appendChild(heading);

우리가 자바스크립트로 생성한 요소는 우리가 직접 화면 어딘가에 명시적으로 추가하기 전까지는 시각적으로 화면에 타나나지 않는다. document.body.appendChild(heading)라는 코드가 없었다면, Heading은 화면에 나타나지 않는다.

append

ParentNode.append() 메서드는 부모요소의 마지막 자식 뒤에 Node 객체 또는 DOMString 객체를 삽입한다. DOMString 객체는 Text 노드처럼 삽입한다.

appendChild

위 메소드는 한 노드를 특정 부모 노드의 자식 노드 리스트 중 마지막 자식으로 붙인다. 만약 주어진 노드가 이미 문서에 존재하는 노드를 참조하고 있다면 appendChild( ) 메소드는 노드를 현재 위치에서 새로운 위치로 이동시킵니다.

append 와 appendChild의 차이점

  • ParentNode.append()는 DOMString 객체도 추가할 수 있다. 한편 Node.appendChild()는 오직 Node 객체만 허용한다.
  • ParentNode.append()는 반환하는 값이 없다. 한편 Node.appendChild()는 추가한 Node 객체를 반환한다.
  • ParentNode.append()는 여러 개 노드와 문자를 추가할 수 있다. 한편 Node.appendChild()는 오직 노드 하나만 추가할 수 있다.

CRUD : READ - QuerySelector, QuerySelectorAll

자바사크립틍데서 원시 자료형인 변수의 값을 조회하기 위해서는 변수의 이름을 직접 조회할 수 있다. 참조자료형인 배열은 index, 객체는 key를 이용해 값을 조회할 수 있다. DOM은 querySelector의 첫 번째 인자로 셀렉터(Selector)를 전달해 확인할 수 있다. 셀렉터로는 HTML태그, id, class가 가장 많이 사용된다.

const one = document.querySelector('.one')

querySelector로 클래스이름이 one인 HTML 엘리먼트를 조회한다.

const ones = document.querySelectorAll('.one')

querySelectorAll로 클래스 이름인 one인 모든 HTML 엘리먼트를 유사배열로 받아온다.
이렇게 조회한 HTML 엘리먼트들은 배열처럼 for문을 사용할 수 있다. 다만 배열이 아니라, 유사배열 혹은 배열형 객체라는 이름으로 기억해야 한다.


CRUD : UPDATE - textContent, classList.add

빈 div 태그를 업데이트하거나, 보다 다양한 작업을 할 수 있다.

console.log(oneDiv) // <div></div>
oneDiv.textContent = 'dev';
console.log(oneDiv) // <div>dev</div>

textContent를 이용해 문자열을 입력할 수 있다.

oneDiv.classList.add('Two')
console.log(oneDiv) // <div class="Two">dev</div>

classList.add를 이용해 'Two'클래스를 추가할 수 있다.


CRUD : DELETE - remove, removeChild

const container = document.querySelector('#container')
const one = document.createElement('div')
container.append(one)
one.remove() // 이렇게 append 했던 엘리먼트를 삭제할 수 있다.

여러 개의 자식 엘리먼트를 지우려면 innerHTML을 이용하면 간단하게 자식엘리먼트를 지울 수 있다.

document.querySelector('#container').innerHTML = '';

❗️ innerHTML은 보안에서 몇 가지 문제를 가지고 있기 때문에 (자세히 보기 removeChild를 사용해 자식 엘리먼트를 지정해서 삭제할 수도 있다.

DOM을 이용하는 것은 자바스크립트 언어를 다루는 것이기 때문에, 마찬가지로 반복문을 활용하면 손쉽게 삭제할 수 있다.

const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
} // 처음 자식 노드를 제외하고 모든 자식 엘리먼트를 제거한다. 

알고 넘어가기 🌟

  • element와 node의 차이
    Node는 태그 노드와 텍스트 노드 전체를 가리키고, Element는 텍스트 노드를 제외하고, 흔히 생각하는 태그만 가리킨다. 따라서 태그만 검색하고 싶을 때는 Element가 붙은 메소드를 선택한다.

  • children과 childNode의 차이
    childNodes의 경우 요소가 아닌 비요소 노드(텍스트)도 포함해주는 반면, element.children은 요소 노드만 배열 형태로 반환해준다.

  • removeChild와 remove의 차이
    remove()는 노드를 메모리에서 삭제하고 종료하는데 반해, removeChild()는 메모리에 해당 노드는 그대로 존재하며, 부모 노드와의 부모-자식관계를 끊어 DOM 트리에서 해제하는 것이다.

  • 유사배열에서 배열로 바꾸는 방법
    ES6에서 추가된 스프레드 연산자 등으로 인해 손쉽게 배열로 바꿀 수 있다.

    1)Array.from(document.querySelectorAll('#list > .item'))
    유사 배열 객체나 반복 가능한 객체를 얕게 복사해 새로운 Array객체를 만드는 방법이다.

    2)Array.slice(document.querySelectorAll('#list > .item'))
    Array.slice()를 사용하는 방법 (참고로 인자로는 start, end값이 들어가는데, end는 생략 가능하다.

    3)[...document.querySelectorAll('#list > .item')]
    스프레드 연산자를 사용하는 방법

  • 노드리스트에서 forEach는 되는데, reduce는 사용할 수 없는 이유
    Nodelist는 배열이 아니라, 노드의 콜렉션이다.그래서 배열 메소드들을 사용할 수 없다.

    Nodelist에 사용가능한 메소드
    Nodelist.item(), Nodelist.entries(), Nodelist.forEach(), Nodelist.keys(), Nodelist.values()

    즉 배열 메소드를 사용할 수 없기 때문에 reduce는 사용이 불가하다.

profile
안녕하세요 주니어 프론트엔드 개발자 양윤성입니다.

0개의 댓글