14. 문서 제어 (14.1~4)

14.1 DOM 트리👊


14.1.1 DOM 트리

웹페이지의 내용은 Document가 관리한다.

웹 브라우저가 웹 페이지를 읽어 들이면 렌더링 엔진은 HTML 문서 구문을 해석하고 DOM 트리라고 하는 객체의 트리 구조를 만든다. DOM 트리를 구성하는 객체 하나를 노드(NODE) 라고 한다. 다음 세 종류가 기본적인 노드다.

  • 문서 노드 : 전체 문서를 가리키는 document 객체
  • HTML 요소 노드 : HTML 요소를 가리키는 객체
  • 텍스트 노드 : 텍스트를 가리키는 객체
    HTML은 공백 문자가 여러 개 있어도 무시하지만 DOM트리는 텍스트로 취급하여 텍스트 노드로 생성한다. 이렇게 공백으로 구성된 텍스트 노드를 공백 노드 라고 한다.

14.1.2 노드 객체의 프로퍼티

프로퍼티 이름설명
parentNode, childNode이 노드의 부모, 자식 노드를 참조
firstChild, lastChild이 노드의 첫번째, 마지막 자식노드, 없을때는 null
nextSibling, previousSibling이 노드와 같은 부모 노드를 가진 다음의, 이전의 형제 노드
nodeType노드 유형을 뜻하는 숫자
nodeValue텍스트 노드의 텍스트 콘텐츠

노드가 가진 이러한 프로퍼티를 활용하면 Document 객체를 타고 내려가 특정 요소 객체나 텍스트 객체를 참조할 수 있다.

노드 프로퍼티를 이용한 HTML문서의 body요소 참조

document.childNodes[0].childNodes[2];
document.firstChild.lastChild;

하지만 이런 방법은 공백 문자의 영향을 많이 받기 때문에 많이 쓰이지 않는다. 보통은 요소의 idclass 속성을 사용하여 원하는 요소 객체를 직접 가져온다.

HTML 요소의 트리

앞에서 이야기 한 것 처럼 공백 문자의 영향 때문에 노드를 참조하면 불편한 점이 있다. 그래서 각 노드에는 DOM트리 안의 텍스트 노드를 무시하고 HTML 문서에서 요소의 계층 구조만 가져오기 위한 프로퍼티가 마련되어 있다.

프로퍼티 이름설명
parentElement, childElement이 요소의 부모, 자식 객체를 참조
firstElementChild, lastElementChild이 요소의 첫번째, 마지막 자식 요소의 객체를 참조
nextElementSibling, previousElementSibling이 요소와 같은 부모를 가진 이 요소 다음의, 이전의 형제 노드

HTML문서 요소의 프로퍼티 이용한 HTML문서의 body요소 참조

document.childNodes[0].childNodes[2];
document.firstChild.lastChild;

14.2 노드 객체 가져오기👊


14.2.1 id 속성으로 노드 가져오기

HTML 문서의 요소에 id 속성을 지정할 수 있다. id 속성값은 문서에서 유일한 값이어야하며 id 속성 값으로 요소 하나를 가리킬 수 있다. getElementById 메서드를 사용한다.

document.getElementById(id 값);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <div id="first">첫번째 div</div>
    <div id="second">두번째 div</div>
    <div id="third">세번째 div</div>
    <script>
      var element = document.getElementById("second");
      element.innerHTML = "여기를 수정함"; // 두번째 div 요소의 내용을 수정한다.
    </script>
  </body>
</html>

14.2.2 요소의 이름으로 노드 가져오기

getElementByTagName 메서드를 사용하면 인수로 넘긴 문자열과 같은 이름을 가진 태그 목록을 가져올 수 있다. 인수로 태그 이름을 넘기고 대소문자를 구별하지 않는다.

document.getElementByTagName(요소의 태그 이름);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <div id="first">첫번째 div</div>
    <div id="second">두번째 div</div>
    <div id="third">세번째 div</div>
    <script>
      var elements = document.getElementsByTagName("div");
      elements[2].innerHTML = "여기를 수정함"; // 두번째 div 요소의 내용을 수정한다.
    </script>
  </body>
</html>

getElementsByTagName 메서드는 NodeList 객체를 반환하고 읽기전용이다.

14.2.3 class 속성 값으로 노드 가져오기

getElementByClassName 메서드를 사용하면 특정 class 속성 값을 class 속성 값으로 가지는 객체 목록(NodeList)을 가져올 수 있다.

document.getElementByClassName(class의 이름);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <div class="cat black">붐베이</div>
    <div class="cat white">페르시안</div>
    <div class="dog white">스피츠</div>
    <script>
      var cats = document.getElementsByClassName("cat");
      for (var i = 0; i < cats.length; i++) {
        console.log(i + "번째 고양이 : " + cats[i].innerHTML);
      }
    </script>
  </body>
</html>

getElementByClassName 메서드는 요소 객체에서도 사용할 수 있다. HTML 문서 안의 첫 번째 p요소의 자식 요소이면서 class 속성 값이 important인 모든 요소의 NodeList를 가져오려면 다음과 같이 작성한다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <p>
      <strong class="important">Document Object Model</strong>의 줄임말입니다.
    </p>
    <script>
      var paras = document.getElementsByTagName("p");
      var firstParaImportants = paras[0].getElementsByClassName("important");
      console.log(firstParaImportants);
    </script>
  </body>
</html>

14.2.4 name 속성 값으로 노드 가져오기

name 속성은 그 요소 이름을 지정할 때 사용하며 form과 input 요소 등의 폼 컨트롤 요소, iframe, img, map, object 요소 등에 지정할 수 있다. name 속성 값은 class 속성 값과 마찬가지로 요소 여러 개를 대상으로 같은 값을 사용할 수 있다.

getElementByName 메서드를 사용한다.

document.getElementByName(class의 이름);
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <form>
      <input type="checkbox" name="dog" value="pome" />포메라니안<br />
      <input type="checkbox" name="dog" value="dalma" />달마시안<br />
      <input type="checkbox" name="dog" value="bool" />불독<br />
    </form>
    <script>
      var dogs = document.getElementsByName("dog");
      dogs[1].value = "corgi";
      dogs[1].nextSibling.nodeValue = "웰시 코기";
      for (var i = 0; i < dogs.length; i++) {
        console.log(`${i}번째의 값 : ${dogs[i].value}`);
      }
    </script>
  </body>
</html>

14.2.5 CSS 선택자로 노드 가져오기

css 선택자는 요소를 가리키기 위한 조건을 제공한다. 예를 들어 다음 선택자는 class 속성 값이 "subtitle"인 p 요소와 일치한다.

p.subtitle; // 클래스 선택자 : 특정 클래스 이름을 포함하는 요소

CSS 선택자를 사용하는 예시

h1                      // 유형 선택자 : 지정한 요소 이름을 가진 요소
*                       // 전체 선택자 : 모든 요소
#title                  // id 선택자
h1[title]               // 속성 선택자
h1[class="maintitle"]   // 속성 선택자 : 지정한 속성 값을 가진 요소
input:checked           // 선택된 라디오 버튼이나 선택된 체크박스 요소
h1:hover                // 마우스 포인터 아레에 있는 h1 요소
#title span             // id값인 title 자손 요소로 존재하는 span 요소
#title > span           // 직계 자식 요소로 존재하는 span 요소
body > h1:first-child   // body 요소의 첫 번째 h1 요소
p, #title               // p 요소와 id 속성 값이 title인 요소

querySelectorAll 메서드를 사용하면 인수로 넘긴 선택자와 일치하는 요소 객체가 담긴 NodeList를 가져올 수 있다.

document.querySelectorAll("선택자");

앞에 나온 것들과는 달리 querySelectorAll 메서드가 반환하는 NodeList는 "살아있는 상태"가 아니다. NodeList에 포함된 요소는 메서드를 호출한 시점에 일치한 요소이다. HTML 문서의 내용이 바뀌어도 NodeList는 바뀌지 않는다. 또한 일치한 요소가 없을 때는 빈 NodeList를 반환한다.

다음 코드는 class 속성 값이 subtitle인 p 요소의 직계 자식 요소인 span 요소가 담긴 NodeList를 반환한다.

var elements = document.querySelectorAll("p.subtitle > span");

querySelector 메서드는 지정한 선택자와 일치하는 요소 객체 중에서 문저 위치가 첫 번째인 요소 객체를 반환한다.

다음 코드는 class 속성 값이 subtitle인 p 요소의 직계 자식 요소 중 첫번째 span 요소를 반환한다.

var elements = document.querySelector("p.subtitle > span");

14.3 속성 값의 읽기와 쓰기👊

이 절에선 요소의 속성 값을 읽고 쓰는 법을 배운다. 또한 속성이 있는지 확인하는법, 삭제하는법, 목록을 가져오는 방법도 배운다.

14.3.1 요소의 속성 값

<a id="school" href="http://www.naver.com">네이버</a>

이 a 요소에는 id 속성과 href 속성이 설정되어 있다. 이처럼 속성은 속성 이름 = 속성 값으로 표기한다.

14.3.2 요소 객체의 프로퍼티로 요소의 속성을 읽고 쓰기

일반적인 속성의 속성 이름은 다음과 같이 표기한다.

요소 객체.속성 이름

이 프로퍼티는 읽기와 쓰기가 가능하다. 위에서 설명한 a요소의 href속성을 다음과 같이 요소 객체의 href 프로퍼티에서 가져올 수 있다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <a id="naver" href="http://www.naver.com">네이버</a>
    <script>
      var anchor = document.getElementById("naver");
      console.log(anchor.href);
    </script>
  </body>
</html>

HTML 요소의 속성 이름은 대소문자를 구분하지 않지만 자바스크립트 요소 객체의 속성 프로퍼티는 대소문자를 구분한다. 속성이름이 여러 단어로 구분되어 있다면 kamelcase 방식으로 두번째 이후 단어의 첫 글자를 대문자로 표기한다.

14.3.3 속성 값 가져오기

요소 객체의 getAttribute 메서드는 요소의 속성을 가져온다. 해당하는 속성이 없을 때는 null 또는 빈 문자열을 반환한다.

요소 객체.getAttribute(속성의 이름)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  </head>
  <body>
    <form id="favorite">
      <input type="checkbox" name="dog" value="pome" />포메라니안<br />
      <input type="checkbox" name="dog" value="dalma" />달마시안<br />
      <input type="checkbox" name="dog" value="bool" />불독<br />
    </form>
    <script>
      var result = [];
      var fm = document.getElementById("favorite");
      var list = fm.children;
      for (var i = 0; i < list.length; i++) {
        if (list[i].nodeName == "INPUT" && list[i].type == "checkbox") {
          result.push(list[i].getAttribute("value"));
        }
      }
      console.log(result.join(","));
    </script>
  </body>
</html>

14.3.4 속성 값 설정하기

요소 객체의 setAttribute 메서드는 요소의 속성을 설정한다. 해당하는 속성이 없을 때는 그 속성을 새롭게 추가한 후에 설정한다.

요소 객체.setAttribute(속성의 이름, 속성 값)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <a id="naver">네이버</a>
    <script>
      let anchor = document.getElementById("naver");
      anchor.setAttribute("href", "http://www.naver.com");
      console.log(anchor);
    </script>
  </body>
</html>

14.3.5 속성이 있는지 확인하기

요소 객체의 hasAttribute 메서드는 속성 이름을 받아서 그 이름을 가진 속성이 있는지 알려주는 논리값을 반환한다.

요소 객체.hasAttribute(속성 이름)


14.3.6 속성 삭제하기

요소 객체의 removeAttribute 메서드는 속성 이름을 받아서 그 이름을 가진 속성을 삭제한다.

요소 객체.removeAttribute(속성 이름)


14.3.7 전체 속성의 목록 가져오기

요소 객체에는 attribute 프로퍼티가 정의되어 있다. 이 프로퍼티틑 NameNodeMap 객체로 그 요소에 설정된 모든 속성의 속성 노드 객체가 담겨 있다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <p id="controls">
      <input type="button" value="click" onclick="doSomething();" />
    </p>
    <script>
      var para = document.getElementById("controls");
      var list = para.firstElementChild.attributes;
      for (var i = 0; i < list.length; i++) {
        console.log(list[i].name + " : " + list[i].value);
      }
    </script>
  </body>
</html>
console.log(list["type"].value); // -> button
console.log(list["value"].value); // -> click
console.log(list.onclick.value); // -> doSomething();

14.4 HTML 요소의 내용을 읽고 쓰기👊

이 절에서는 요소의 내용을 읽고 쓰는 방법을 배운다.

요소의 내용이라는 단어에는

  1. 요소 안의 HTML 코드 (innerHTML)
  2. 요소를 웹 페이지에 표시할 때의 텍스트 정보 (textContent, innerText)
  3. 요소 객체 안의 노드의 계층 구조라는 세 가지 의미가 함축되어 있다.

14.4.1 innerHTML 프로퍼티

innerHTML 프로퍼티를 사용해서 요소 안의 코드를 읽거나 쓸 수 있다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <h1>하트</h1>
    <p id="cards">&hearts;하트는 <em>승려</em>라는 뜻입니다.</p>
    <script>
      let para = document.getElementById("cards");
      console.log(textContent(para));
    </script>
  </body>
</html>

이 코드에 innerHTML 프로퍼티로 p 요소의 내용을 수정하면 요소의 내용이 대입한 코드로 바뀐다.

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <p id="cards">&hearts;하트는 <em>승려</em>라는 뜻입니다.</p>
    <script>
      let para = document.getElementById("cards");
      para.innerHTML = "&diams;다이아는 <string>상인</strong>이라는 뜻입니다.";
      console.log(para.innerHTML);
    </script>
  </body>
</html>

14.4.2 textContent와 innerText 프로퍼티

textContent 프로퍼티는 요소의 내용을 웹 페이지에 표시했을 때의 텍스트 정보를 표시합니다. 또한 textContent 프로퍼티에 텍스트를 대입하면 요소의 내용을 텍스트로 변환할 수 있다.

para.textContent = "&diams;다이아는 <strong>상인</strong>이라는 뜻입니다.";
console.log(para.innerHTML);
// -> &amp;diams;다이아는 &lt;string&gt;상인&lt;/strong&gt;이라는 뜻입니다.
console.log(para.textContent);
// -> &diams;다이아는 <string>상인</strong>이라는 뜻입니다.

textContent와 innerText 프로퍼티는 거의 같은 일을 하지만 다음과 같은 차이점이 있다.

  • textContent는 script 요소 안의 텍스트를 반환하지만 innerText는 반환하지 않는다.
  • textContent는 공백 문자를 그대로 반환하지만 innerText는 남는 공백 문자를 제거한다.
  • innerText는 table, tbody, tr 요소 등의 테이블 요소를 수정할 수 없다.

좋은 웹페이지 즐겨찾기