DOM(Document Object Model)

heyj·2022년 2월 22일
0

HTML/CSS/Javascript

목록 보기
6/8
post-thumbnail

DOM은 Document Object Model의 약자로, XML이나 HTML 문서에 접근하기 위한 인터페이스입니다. 프로그래밍 언어가 DOM구조에 접근할 수 있는 방법을 제공하여 문서 구조, 스타일 내용 등을 변경 할 수 있게 합니다.

DOM과 HTML

DOM은 단순 텍스트로 구성된 HTML문서의 내용과 구조를 객체 모델로 변환한 것이라고 할 수 있습니다.

우리가 보는 웹 페이지가 만들어지는 과정을 간략하게 2단계로, 첫째 브라우저가 HTML 문서를 읽고 파싱해 어떤 것을 렌더링 할지 정하고, 둘째 브라우저가 실제 렌더링을 수행하는 것으로 나눌 수 있습니다.

브라우저가 어떤 것을 렌더링할지 정하는 과정에서 'Render Tree'가 형성되는데, 이 때 DOM과 CSSOM이 필요합니다.

DOM 예제

<!DOCTYPE HTML>
<html>
  <head>
    <title>우리동내</title>
  </head>
  <body>
    <span>우리동내 맛집보기</span>
  </body>
</html>

DOM은 이 HTML 문서를 아래와 같이 트리 구조로 표현합니다.

DOM과 Javascript

DOM은 프로그래밍 언어가 아니지만, DOM이 없으면 자바스크립트 언어는 HTML, XML 및 요소들에 접근하지 못합니다. 위의 DOM 예제에서 보이는 span 태그 등에 자바스크립트와 같은 스크립팅 언어를 통해 접근하고 조작할 수 있습니다.

<span class="text">우리동내 맛집보기</span>
const text = document.querySelector('.text')

DOM으로 HTML조작하기

지금부터는 아래 예제를 구현하면서 HTML 조작하는 방법을 알아보도록 하겠습니다.

간단히 html을 작성했습니다.

<section class="List">
  <header class="header">
    Shopping List
  </header>
  <ul class="items">
	<!-- item list가 들어갈 곳 -->
  </ul>
  <form class="new-form">
    <footer class="footer">
      <input type="text" id="footer_input" />
      <button type="submit" class="footer_button">+
      </button>
    </footer>
  </form>
</section>

1. Read

기능을 구현하기에 앞서 어느 요소에 아이템을 넣을건지 결정합니다. 또 input에서도 값을 받아와야 합니다.

위 예제에서는 footer input과 생성된 li 태그들을 위치시켜줄 ul 태그를 가져와야 합니다. 이 때는 querySelector을 이용합니다. 여러 개의 element를 한 번에 가져오기 위해서는 querySelectorAll을 이용합니다.

document.querySelector();
document.querySelectorAll();

앞서 html을 작성하며 조작이 필요한 요소에 class 이름, id를 부여했습니다. class 이름으로 element를 조회할 때는 '.className'으로, id로 조회할 때는 '#id'로 접근할 수 있습니다.

// class 이름이 items인 것을 찾아 조회
const items = document.querySelector(".items");

// id가 footer_input인 것을 찾아 조회
const input = document.querySelector("#footer_input");

2. Create

html요소를 가져왔으므로 이제 생성을 위한 로직을 작성합니다.
list에 item을 넣으려면 새로운 elements를 생성해야 합니다. 이 때 createElement를 이용합니다.

document.createElement()

이 예제에서는 유저가 input에 값을 넣으면 submit함수가 실행되어 element를 생성하므로, createItem함수를 만들어 줍니다.

let id = 0;

function createItem(text) {
  const itemRow = document.createElement("li");
  id++;
  return itemRow;
}

이 함수만으로는 아무일도 일어나지 않습니다. 생성된 element를 트리 구조와 연결하는 함수가 없기 때문입니다. 연결을 위해서는 append, appendChild를 이용합니다.

document.body.append()
document.body.appendChild()

이것을 이용해 addItem함수를 만듭니다.

function addItem() {
  const text = input.value;
  if (text === "") {
    input.focus();
    return;
  }
  const item = createItem(text);
  items.appendChild(item)
  input.value = "";
  input.focus();

3. setAttribute, innerHTML

사실 앞서 만든 createItem는 li 태그를 생성하지만, 내용물은 아무것도 없습니다. 유저가 입력한 값이 화면에 보이도록 하고 CSS 등 적용을 위한 작업을 진행해야 합니다.

이 때 태그에 속성을 부여할 수 있는 메소드가 setAttribute입니다. class는 classList.add로도 추가가 가능합니다.

element.setAttribute()
element.classList.add()

각각의 item에 클래스이름과 data-id를 부여해줬습니다.

function createItem(text) {
  const itemRow = document.createElement("li");
    itemRow.setAttribute("class", "item_row");
    itemRow.setAttribute("data-id", id);
    id++;
  return itemRow;
}

이제 CSS도 적용이 가능하고, 이 element에 자바스크립트를 이용한 접근도 가능해졌습니다. 그런데 유저는 화면에서 아무것도 볼 수 없습니다. text 등 내용이 없어서요 하하;

내용을 넣는 방법은 다양합니다. text만 넣을거면 innerText, textContent를 이용할 수 있습니다. 만약 text뿐 아니라 다른 요소들도 추가해야 한다면 innerHTML을 사용하면 됩니다.

element.innerText()
element.textContent()
element.innerHTML()

innerHTML, innerText, textContent?

  • innerHTML은 element 속성으로 해당 element의 html, xml을 읽어오거나 설정할 수 있습니다. html 마크업이 포함된 것을 생성하고 싶다면 이를 사용합니다.
  • innerText 역시 element 속성으로 element 내에 사용자에게 보여지는 텍스트 값을 읽어오거나 수정할 수 있습니다. html마크업은 문자열 그대로 취급됩니다.
  • textContent는 node속성으로 innerText와 달리 js, css 속성과 관계없이 해상 노드가 가지고 있는 텍스트 값을 그대로 읽습니다. innerText는 빈칸이 없는 값을 반환하는 반면, textContent는 반칸을 모두 포함한 text를 반환합니다. html마크업은 문자열 그대로 취급됩니다.

이번 예제에서는 새로운 element를 추가하고 스타일링을 위한 클래스도 부여해야 하므로 innerHTML을 사용합니다.

itemRow.innerHTML = `<div class="item">
	<span class="item_name">${text}</span>
	<button class="item_delete" data-id=${id}>+
	</button>
	</div>
	<div class="item_divider"></div>
`;

4. Remove

우유, 계란을 샀으면 이제는 쇼핑리스트에서 지워줘야 합니다.

우선 아이템 생성과 함께 만들었던 delete 버튼이 필요합니다. element를 가져오고, eventListener를 만들어 기능을 구현합니다.

element.addEventListener(userEvent, 함수)

element.remove()
element.removeChild()

remove()는 노드를 메모리에서 삭제하고 종료하는 반면, removeChild()는 메모리에 해당 노드는 그대로 존재하지만 DOM트리에서 해제시키는 방식으로 동작합니다. 최종적으로 관계를 끊은 노드의 레퍼런스를 반환합니다.

여기서는 필요 없는 노드들을 모두 삭제해야 하므로 아이템을 지울 때 remove메소드를 사용하겠습니다.

이 예제에서는 각각의 item에 id를 부여했기 때문에 해당 id의 element를 모두 지원주도록 구현하면 됩니다.


items.addEventListener("click", (event) => {
  const id = event.target.dataset.id;
  if (id) {
    const toBedeleted = document.querySelector(`.item_row[data-id="${id}"]`);
    toBedeleted.remove();
  }
});

만약 element는 그대로 두고 안의 text만 지우고 싶다면 innerText, textContent 값을 비워주면 됩니다.

element.innerText = "";
element.textContent = "";

마치며

마지막으로 form 태그까지 연결해주면 끝이 납니다.

const form = document.querySelector(".new-form");

form.addEventListener("submit", (event) => {
  event.preventDefault();
  onAdd();
});

심화학습을 위한 주제
1. difference between element and node in JS dom
2. why array method is not working on nodelist
3. how to convert nodelist into JS array

참고
https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Introduction
https://wit.nts-corp.com/2019/02/14/5522
https://ko.javascript.info/dom-nodes
https://hianna.tistory.com/483

0개의 댓글