Language/Javascript

[Javascript] 자바스크립트 문서 객체 모델 - DOM 선택, 변경, 메소드

재은초 2023. 8. 4. 00:22
반응형

문서 객체 모델(DOM)이란?

  • 텍스트 파일로 이루어진 웹 문서를 브라우저에 렌더링하려면 웹 문서를 브라우저가 이해할 수 있는 구조로 만들어 메모리에 올려야 한다. 브라우저의 렌더링 엔진은 웹 문서(HTML, XML, SVG)를 로드한 후 파싱하여, 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM(문서 객체 모델: Document Object Model)이라 한다.
  • 즉, 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이들 객체를 부자 관계를 표현할 수 있는 트리 구조로 구성한 것이 DOM이다. 이 DOM은 자바스크립트를 통해 동적으로 변경할 수 있으며 변경된 DOM은 렌더링에 반영된다. 
  • 정적인 웹페이지에 접근하여 동적으로 웹페이지를 변경하기 위해 DOM은 프로그래밍 언어가 자신에 접근하고 수정할 수 있는 방법을 프로퍼티와 메소드를 갖는 자바스크립트 객체로 제공하는데 이를 DOM API라고 부른다.
  • DOM을 통해 웹페이지를 조작(manipulate)하기 위해서는 ① 조작하고자하는 요소를 선택 또는 탐색하고  선택된 요소의 콘텐츠 또는 어트리뷰트를 조작하면 된다. 자바스크립트는 이것에 필요한 수단(API)을 제공한다.
  • DOM은 HTML, ECMAScript에서 정의한 표준이 아닌 별개의 W3C의 공식 표준이며 플랫폼/프로그래밍 언어 중립적이다. DOM은 다음 두 가지 기능을 담당한다.
    • HTML 문서에 대한 모델 구성 : 브라우저는 HTML 문서를 로드한 후 해당 문서에 대한 모델을 메모리에 생성한다. 이때 모델은 객체의 트리로 구성되는데 이것을 DOM tree라 한다.
    • HTML 문서 내의 각 요소에 접근 / 수정 : DOM은 모델 내의 각 객체에 접근하고 수정할 수 있는 프로퍼티와 메소드를 제공한다. DOM이 수정되면 브라우저를 통해 사용자가 보게 될 내용 또한 변경된다.
https://poiemaweb.com/js-dom
  • 문서 객체 모델(DOM, Document Object Model)은 XML이나 HTML 문서에 접근하기 위한 일종의 인터페이스로, 이 객체 모델은 문서 내의 모든 요소를 정의하고 각각의 요소에 접근하는 방법을 제공한다.
  • 자바스크립트는 문서 객체 모델을 이용하여 HTML 요소나 속성을 추가/제거/변경과 HTML 이벤트 추가/반응, CSS 스타일을 변경할 수 있다.
  • 문서 객체 모델은 W3C의 표준 객체 모델이며, 아래같은 계층 구조로 표현된다.
http://www.tcpschool.com/javascript/js_dom_concept

 

DOM의 종류

  • W3C DOM 표준은 세 가지 모델로 구분된다.
    • Core DOM : 모든 문서 타입을 위한 DOM 모델
    • HTML DOM : HTML 문서를 조작하고 접근하는 표준화된 방법을 정의하며, 모든 HTML 요소는 HTML DOM를 통해 접근할 수 있다.
    • XML DOM : XML 문서에 접근하여 그 문서를 다루는 표준화된 방법을 정의하며, 모든 XML 요소는 XML DOM를 통해 접근할 수 있다.

 

DOM의 기능

DOM tree

  • DOM tree는 브라우저가 HTML 문서를 로드한 후 파싱하여 생성하는 모델을 의미한다. 객체의 트리로 구조화되어 있기 때문에 DOM tree라 부른다.
  • DOM에서 모든 요소, 어트리뷰트, 텍스트는 하나의 객체이며 Document 객체의 자식이다. 요소의 중첩관계는 객체의 트리로 구조화하여 부자관계를 표현한다. DOM tree의 진입점(Entry point)는 document 객체이며 최종점은 요소의 텍스트를 나타내는 객체이다.
https://poiemaweb.com/js-dom
  • DOM tree는 네 종류의 노드로 구성된다.
    • 문서 노드(Document Node) : 트리의 최상위에 존재하며 각각 요소, 어트리뷰트, 텍스트 노드에 접근하려면 문서 노드를 통해야 한다. 즉, DOM tree에 접근하기 위한 시작점(entry point)이다.
    • 요소 노드(Element Node) : 요소 노드는 HTML 요소를 표현한다. HTML 요소는 중첩에 의해 부자 관계를 가지며 이 부자 관계를 통해 정보를 구조화한다. 따라서 요소 노드는 문서의 구조를 서술한다고 말 할 수 있다. 어트리뷰트, 텍스트 노드에 접근하려면 먼저 요소 노드를 찾아 접근해야 한다. 모든 요소 노드는 요소별 특성을 표현하기 위해 HTMLElement 객체를 상속한 객체로 구성된다.
    • 어트리뷰트 노드(Attribute Node) : 어트리뷰트 노드는 HTML 요소의 어트리뷰트를 표현한다. 어트리뷰트 노드는 해당 어트리뷰트가 지정된 요소의 자식이 아니라 해당 요소의 일부로 표현된다. 따라서 해당 요소 노드를 찾아 접근하면 어트리뷰트를 참조, 수정할 수 있다.
    • 텍스트 노드(Text Node) : 텍스트 노드는 HTML 요소의 텍스트를 표현한다. 텍스트 노드는 요소 노드의 자식이며 자신의 자식 노드를 가질 수 없다. 즉, 텍스트 노드는 DOM tree의 최종단이다.
https://poiemaweb.com/js-dom
<!DOCTYPE html>
<html>
  <head>
    <style>
      .red  { color: #ff0000; }
      .blue { color: #0000ff; }
    </style>
  </head>
  <body>
    <div>
      <h1>Cities</h1>
      <ul>
        <li id="one" class="red">Seoul</li>
        <li id="two" class="red">London</li>
        <li id="three" class="red">Newyork</li>
        <li id="four">Tokyo</li>
      </ul>
    </div>
  </body>
</html>

 

DOM 요소 접근

하나의 요소 노드 선택

아이디(id)를 이용한 선택

  • getElementById() 메소드는 id 어트리뷰트 값으로 요소 노드를 한 개 선택한다. 복수개가 선택된 경우, 첫번째 요소만 반환한다.
// 아이디가 even인 요소 선택
var selectedItem = document.getElementById("even"); 

selectedItem.style.color = "red";                // 선택된 요소의 글자색 변경

CSS 선택자(selector)를 이용한 선택

  • querySelector() 메소드는 CSS 셀렉터를 사용하여 요소 노드를 한 개 선택한다. 복수개가 선택된 경우, 첫번째 요소만 반환한다.
// CSS 셀렉터를 이용해 요소를 선택한다
const elem = document.querySelector('li.red');

// 클래스 어트리뷰트의 값을 변경한다
elem.className = 'blue';

여러 개의 요소 노드 선택

클래스(class)를 이용한 선택

  • getElementsByClassName() 메소드는 class 어트리뷰트 값으로 요소 노드를 모두 선택한다. 공백으로 구분하여 여러 개의 class를 지정할 수 있다.
// 클래스가 odd인 모든 요소 선택
var selectedItem = document.getElementsByClassName("odd");

for (var i = 0; i < selectedItem.length; i++) {
    selectedItem.item(i).style.color = "red"; // 선택된 모든 요소 글자색 변경
}

HTML 태그 이름(tag name)을 이용한 선택

  • getElementsByTagName() 메소드는 태그명으로 요소 노드를 모두 선택한다.
// 모든 <li> 요소선택
var selectedItem = document.getElementsByTagName("li");

// item() 메소드는 해당 HTML 객체 집합에서 전달받은 인덱스에 해당하는 요소 반환
for (var i = 0; i < selectedItem.length; i++) {
    selectedItem.item(i).style.color = "red";   // 선택된 모든 요소 글자색 변경
}

CSS 선택자(selector)를 이용한 선택

  • querySelectorAll() 메소드는 지정된 CSS 선택자를 사용하여 요소 노드를 모두 선택한다.
// 클래스가 odd인 요소 중에서 <li> 요소만 선택
var selectedItem = document.querySelectorAll("li.odd"); 

for (var i = 0; i < selectedItem.length; i++) {
    selectedItem.item(i).style.color = "red"; // 선택된 모든 요소 글자색 변경
}

name 속성을 이용한 선택

  • getElementByName() 메소드는 HTML 요소의 name 속성을 이용하여 HTML 요소를 선택한다.
// name 속성값이 first인 모든 요소 선택
var selectedItem = document.getElementsByName("first"); 

for (var i = 0; i < selectedItem.length; i++) {
    selectedItem.item(i).style.color = "red"; // 선택된 모든 요소 글자색 변경
}

HTML 객체 집합(object collection)을 이용한 선택

  • HTML DOM에서 제공하는 객체 집합을 이용하여 HTML 요소를 선택할 수 있다.
var title = document.title; // <title> 요소 선택
document.write(title);

 

DOM 요소 탐색

  • parentNode로 부모 노드를 탐색한다.
const elem = document.querySelector('#two');

elem.parentNode.className = 'blue';
  • firstChild, lastChild로 자식 노드를 탐색한다.
const elem = document.querySelector('ul');

// first Child
elem.firstChild.className = 'blue';
// last Child
elem.lastChild.className = 'blue';
const elem = document.querySelector('ul');

// first Child
elem.firstElementChild.className = 'blue';
// last Child
elem.lastElementChild.className = 'blue';
  • hasChildNodes()로 자식 노드가 있는지 확인하고 Boolean 값을 반환한다.
  • childNodes로 자식 노드의 컬렉션을 반환한다. 텍스트 요소를 포함한 모든 자식 요소를 반환한다.
  • children로 자식 노드의 컬렉션을 반환한다. 자식 요소 중에서 Element type 요소만을 반환한다.
const elem = document.querySelector('ul');

if (elem.hasChildNodes()) {
  console.log(elem.childNodes);
  // 텍스트 요소를 포함한 모든 자식 요소를 반환한다.
  // NodeList(9) [text, li#one.red, text, li#two.red, text, li#three.red, text, li#four, text]

  console.log(elem.children);
  // 자식 요소 중에서 Element type 요소만을 반환한다.
  // HTMLCollection(4) [li#one.red, li#two.red, li#three.red, li#four, one: li#one.red, two: li#two.red, three: li#three.red, four: li#four]
  [...elem.children].forEach(el => console.log(el.nodeType)); // 1 (=> Element node)
}
  • previousSibling, nextSibling로 형제 노드를 탐색한다. text node를 포함한 모든 형제 노드를 탐색한다.
  • previousElementSibling, nextElementSibling로 형제 노드를 탐색한다. 형제 노드 중에서 Element type 요소만을 탐색한다.
const elem = document.querySelector('ul');

elem.firstElementChild.nextElementSibling.className = 'blue';
elem.firstElementChild.nextElementSibling.previousElementSibling.className = 'blue';

 

DOM 요소 조작

텍스트 노드에의 접근 및 수정

  • nodeValue로 노드의 값을 반환한다.
// 해당 텍스트 노드의 부모 요소 노드를 선택한다.
const one = document.getElementById('one');
console.dir(one); // HTMLLIElement: li#one.red

// nodeName, nodeType을 통해 노드의 정보를 취득할 수 있다.
console.log(one.nodeName); // LI
console.log(one.nodeType); // 1: Element node

// firstChild 프로퍼티를 사용하여 텍스트 노드를 탐색한다.
const textNode = one.firstChild;

// nodeName, nodeType을 통해 노드의 정보를 취득할 수 있다.
console.log(textNode.nodeName); // #text
console.log(textNode.nodeType); // 3: Text node

// nodeValue 프로퍼티를 사용하여 노드의 값을 취득한다.
console.log(textNode.nodeValue); // Seoul

// nodeValue 프로퍼티를 이용하여 텍스트를 수정한다.
textNode.nodeValue = 'Pusan';

어트리뷰트 노드에의 접근/수정

  • className으로 class 어트리뷰트의 값을 취득 또는 변경한다.
  • className 프로퍼티에 값을 할당하는 경우, class 어트리뷰트가 존재하지 않으면 class 어트리뷰트를 생성하고 지정된 값을 설정한다. class 어트리뷰트의 값이 여러 개일 경우, 공백으로 구분된 문자열이 반환되므로 String 메소드 split(' ')를 사용하여 배열로 변경하여 사용한다.
  • classList는 add, remove, item, toggle, contains, replace 메소드를 제공한다.
const elems = document.querySelectorAll('li');

// className
[...elems].forEach(elem => {
  // class 어트리뷰트 값을 취득하여 확인
  if (elem.className === 'red') {
    // class 어트리뷰트 값을 변경한다.
    elem.className = 'blue';
  }
});

// classList
[...elems].forEach(elem => {
  // class 어트리뷰트 값 확인
  if (elem.classList.contains('blue')) {
    // class 어트리뷰트 값 변경한다.
    elem.classList.replace('blue', 'red');
  }
});
  • id로 id 어트리뷰트의 값을 취득 또는 변경한다. id 프로퍼티에 값을 할당하는 경우, id 어트리뷰트가 존재하지 않으면 id 어트리뷰트를 생성하고 지정된 값을 설정한다.
// h1 태그 요소 중 첫번째 요소를 취득
const heading = document.querySelector('h1');

console.dir(heading); // HTMLHeadingElement: h1
console.log(heading.firstChild.nodeValue); // Cities

// id 어트리뷰트의 값을 변경.
// id 어트리뷰트가 존재하지 않으면 id 어트리뷰트를 생성하고 지정된 값을 설정
heading.id = 'heading';
console.log(heading.id); // heading
  • hasAttribute(attribute)로 지정한 어트리뷰트를 가지고 있는지 검사한다.
  • getAttribute(attribute)로 어트리뷰트의 값을 취득한다.
  • setAttribute(attribute, value)로 어트리뷰트와 어트리뷰트 값을 설정한다.
  • removeAttribute(attribute)로 지정한 어트리뷰트를 제거한다.
<!DOCTYPE html>
<html>
  <body>
  <input type="text">
  <script>
  const input = document.querySelector('input[type=text]');
  console.log(input);

  // value 어트리뷰트가 존재하지 않으면
  if (!input.hasAttribute('value')) {
    // value 어트리뷰트를 추가하고 값으로 'hello!'를 설정
    input.setAttribute('value', 'hello!');
  }

  // value 어트리뷰트 값을 취득
  console.log(input.getAttribute('value')); // hello!

  // value 어트리뷰트를 제거
  input.removeAttribute('value');

  // value 어트리뷰트의 존재를 확인
  console.log(input.hasAttribute('value')); // false
  </script>
  </body>
</html>

DOM 요소의 스타일 변경

  • HTML DOM을 이용하면 HTML 요소의 스타일도 손쉽게 변경할 수 있다.
/* style 프로퍼티를 이용한 HTML 요소의 CSS 스타일 적용 */
var str = document.getElementById("text");      // 아이디가 text인 요소 선택
function changeRedColor() { str.style.color = "red"; }     // 빨강으로 변경
function changeBlackColor() { str.style.color = "black"; } // 검정으로 변경

 

HTML 콘텐츠 조작

  • textContent로 요소의 텍스트 콘텐츠를 취득 또는 변경한다. 이때 마크업은 무시된다. textContent를 통해 요소에 새로운 텍스트를 할당하면 텍스트를 변경할 수 있다. 이때 순수한 텍스트만 지정해야 하며 마크업을 포함시키면 문자열로 인식되어 그대로 출력된다.
<!DOCTYPE html>
<html>
  <head>
    <style>
      .red  { color: #ff0000; }
      .blue { color: #0000ff; }
    </style>
  </head>
  <body>
    <div>
      <h1>Cities</h1>
      <ul>
        <li id="one" class="red">Seoul</li>
        <li id="two" class="red">London</li>
        <li id="three" class="red">Newyork</li>
        <li id="four">Tokyo</li>
      </ul>
    </div>
    <script>
    const ul = document.querySelector('ul');

    // 요소의 텍스트 취득
    console.log(ul.textContent);
    /*
            Seoul
            London
            Newyork
            Tokyo
    */

    const one = document.getElementById('one');

    // 요소의 텍스트 취득
    console.log(one.textContent); // Seoul

    // 요소의 텍스트 변경
    one.textContent += ', Korea';

    console.log(one.textContent); // Seoul, Korea

    // 요소의 마크업이 포함된 콘텐츠 변경.
    one.textContent = '<h1>Heading</h1>';

    // 마크업이 문자열로 표시된다.
    console.log(one.textContent); // <h1>Heading</h1>
    </script>
  </body>
</html>
  • innerHTML로 해당 요소의 모든 자식 요소를 포함하는 모든 콘텐츠를 하나의 문자열로 취득할 수 있다. 이 문자열은 마크업을 포함한다.
/* innerHTML 프로퍼티를 이용한 HTML 요소의 내용 변경 */
var str = document.getElementById("text");
str.innerHTML = "이 문장으로 바뀌었습니다!";
/* HTML 요소의 속성 이름을 이용하면 속성값도 변경 */
var link = document.getElementById("link");   // 아이디가 link인 요소 선택
link.href = "/javascript/intro";              // 해당 요소의 href 속성값 변경
link.innerHTML = "자바스크립트 수업 바로 가기!";     // 해당 요소의 내용 변경

 

DOM 조작 방식

  • createElement(tagName)로 태그이름을 인자로 전달하여 새로운 요소를 생성한다.
  • createTextNode(text)로 텍스트를 인자로 전달하여 새로운 텍스트 노드를 생성한다. 경우에 따라 생략될 수 있지만 생략하는 경우, 콘텐츠가 비어 있는 요소가 된다.
  • appendChild(Node)로 인자로 전달한 노드를 마지막 자식 요소로 DOM 트리에 추가한다.
  • removeChild(Node)로 인자로 전달한 노드를 DOM 트리에 제거한다.
// 태그이름을 인자로 전달하여 요소를 생성
const newElem = document.createElement('li');
// const newElem = document.createElement('<li>test</li>');
// Uncaught DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('<li>test</li>') is not a valid name.

// 텍스트 노드를 생성
const newText = document.createTextNode('Beijing');

// 텍스트 노드를 newElem 자식으로 DOM 트리에 추가
newElem.appendChild(newText);

const container = document.querySelector('ul');

// newElem을 container의 자식으로 DOM 트리에 추가. 마지막 요소로 추가된다.
container.appendChild(newElem);

const removeElem = document.getElementById('one');

// container의 자식인 removeElem 요소를 DOM 트리에 제거한다.
container.removeChild(removeElem);
  • insertAdjacentHTML(position, string)로 인자로 전달한 텍스트를 HTML로 파싱하고 그 결과로 생성된 노드를 DOM 트리의 지정된 위치에 삽입한다. 첫번째 인자는 삽입 위치, 두번째 인자는 삽입할 요소를 표현한 문자열이다. 첫번째 인자로 올 수 있는 값은 beforebegin, afterbegin, beforeend, afterend와 같다.
const one = document.getElementById('one');

// 마크업이 포함된 요소 추가
one.insertAdjacentHTML('beforeend', '<em class="blue">, Korea</em>');

 

Document 객체

  • Document 객체는 웹 페이지 그 자체를 의미하며, 웹 페이지에 존재하는 HTML 요소에 접근하고자 할 때는 반드시 Document 객체부터 시작해야 한다.

 

Document 메소드

HTML 요소의 선택

  • document.getElementsByTagName(태그이름) : 해당 태그 이름의 요소를 모두 선택한다.
  • document.getElementById(아이디) : 해당 아이디의 요소를 선택한다.
  • document.getElementsByClassName(클래스이름) : 해당 클래스에 속한 요소를 모두 선택한다.
  • document.getElementsByName(name속성값) : 해당 name 속성값을 가지는 요소를 모두 선택한다.
  • document.querySelectorAll(선택자) : 해당 선택자로 선택되는 요소를 모두 선택한다.

HTML 요소의 생성

  • document.createElement(HTML요소) : 지정된 HTML 요소를 생성한다.
  • document.write(텍스트) : HTML 출력 스트림을 통해 텍스트를 출력한다.

HTML 이벤트 핸들러 추가

  • document.getElementById(아이디).onclick = function(){ 실행할 코드 } : 마우스 클릭 이벤트와 연결될 이벤트 핸들러 코드를 추가한다.

HTML 객체의 선택

  • HTML DOM에서 제공하는 객체 집합(object collection)을 이용하면 HTML 객체를 손쉽게 선택할 수 있다.

http://www.tcpschool.com/javascript/js_dom_document

 

Reference

반응형