노드(node)

노드란?

  • html문서는 노드라는 계층구조에 정보들을 저장한다. DOM은 노드들을 정리하고 그들 사이의 관계를 설명해주는 역할을 한다. 예) 자식노드, 부모노드
  • 노드간의 관계들을 정리해 모아놓은것을 노드트리라고 한다. 노드트리는 최상위 레벨인 루트노드(root node)로 시작하여 가장 낮은 레벨인 텍스트 노드까지로 이루어져 있다.
  • 자바스크립트는 DOM을 이용하여 모든 노드에 접근할 수 있다.

노드의 종류

  • HTML 문서의 모든 것은 노드다. HTML문서를 구성하는 노드들의 대략적인 타입은 아래와 같이 나누어져 있다. DOM으로 접근할 수 있는 요소들이라고 이해하면 된다.
  • 문서노드(document node) - html문서 전체를 가리키는 노드다.
  • 요소노드(element node) - 모든 html 요소를 가리킨다. 속성노드를 가질 수 있는 유일한 노드다.
  • 속성노드(attribute node) - 속성노드들은 요소노드에 대한 정보를 가지고 있다. 하지만 속성요소가 자식요소로 포함되지는 않는다.
  • 텍스트노드(text node) - 모든 텍스트는 텍스트 노드다.
  • 주석노드(comment node) - 모든 주석은 주석 노드다.

노드간의 관계

노드트리

설명
  • 모든 노드는 단 하나의 부모 노드를 가진다. (루트노드제외)
  • 형제노드란 같은 부모노드를 가진 노드들을 가리킨다.
  • 조상노드란 부모노드를 포함해 계층적으로 현재노드보다 상위에 존재하는 노드를 가리킨다.
  • 자손노드란 자식노드를 포함해 계층적으로 현재노드보다 하위에 존재하는 노드를 가리킨다.
예시 (그림 기반)
  • <header>와 <div>, <footer>는 같은 부모노드를 가진 형제노드다. (모두 body가 부모노드다.)
  • <li>의 조상노드는 html, body, div, ul 이다.
  • <div>의 자손노드는 ul, li 이다.
노드간의 관계를 이용해 접근하는 법
  • 노드간의 관계는 아래와 같은 프로퍼티들로 정의된다. 다음의 프로퍼티들을 활용해 원하는 노드로 접근할 수 있다.
  • parentNode - 부모노드
  • childNodes - 자식 노드 리스트
  • firstChild - 첫 번째 자식 노드
  • lastChild - 마지막 자식 노드
  • nextSibling - 다음 형제 노드
  • previousSibling - 이전 형제 노드
빈 텍스트 처리
  • 현재 대부분의 브라우저는 모두 DOM을 지원하고 있지만 처리방식에 있어 약간의 차이를 가지고 있다.
  • 익스플로러를 제외한 많은 브라우저들은 띄어쓰기나 줄바꿈을 텍스트노드(text node)로 취급한다.
  • 따라서 자식노드나 형제노드를 이용해 원하는 노드에 접근하려고 하면 브라우저간에 차이가 발생할 수 있다.
  • 이를 아래 나오는 nodeType 프로퍼티를 사용해 선택된 요소의 타입을 검사하는 방법으로 해결할 수 있다.
  • (예를들어 내가 찾은 요소의 타입이 요소노드가 아니면, 다시 검사하는 식으로 해결한다.)

노드 정보

  • 노드는 3가지의 프로퍼티를 가지고 있다. 이 프로퍼티들을 이용해 노드의 정보를 확인할 수 있다.
  • nodeName, nodeValue, nodeType
nodeName
  • nodeName 프로퍼티는 노드 고유의 이름을 저장한다. 수정할 수 없는 읽기 전용 프로퍼티 이며, 노드별 nodeName의 프로퍼티는 아래와 같다.
  • 문서노드 : #document
  • 요소노드 : 해당 요소의 이름을 대문자로 저장한다. (div일 경우 DIV)
  • 속성노드 : 속성의 이름을 저장한다.
  • 텍스트노드 : #text
nodeValue
  • nodeValue 프로퍼티는 노드의 값을 저장한다.
  • 요소노드 : undefined
  • 속성노드 : 해당 속성의 속성값
  • 텍스트노드 : 해당 텍스트의 문자열
nodeType
  • nodeType 프로퍼티는 노드 고유의 타입을 저장한다. 수정할 수 없는 읽기 전용 프로퍼티
  • 요소노드 : 1
  • 속성노드 : 2
  • 텍스트노드 : 3
  • 주석노드 : 8
  • 문서노드 : 9
노드리스트
  • 노드리스트는 getElementsByTagName() 이나, childNodes 프로퍼티의 값으로 반환되는 객체다.
  • 리스트의 각 노드는 인덱스 번호를 이용하여 접근할 수 있다.
  • 빈 텍스트도 텍스트 노드로 인식하여 인덱스 번호를 부여하므로 노드리스트에서 인덱스 번호로 접근할 경우에는 이를 염두해 두어야 한다.

노드의 관리

노드의 추가
  • appendChild() : 새로운 노드를 해당 노드의 자식노드리스트 맨 마지막에 추가한다.
  • insertBefore() : 새로운 노드를 특정 자식 노드 바로 앞에 추가한다.
  • insertData() : 텍스트 노드를 텍스트 데이터에 새로운 텍스트로 추가한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<!-- 공통 -->
<div>
    <p id="item">안녕</p>
    <div id="list">
        <p>가나다</p>
        <p id="last">라마바</p>
    </div>
</div>
 
<script>
    const item = document.getElementById("item"),
          list = document.getElementById("list"),
          lastList = document.getElementById("last");
 
    /* appendChild */
    /* 기본형 : 특정노드.appendChild(추가할노드) */
    list.appendChild(item); //결과 : <p id="last">라마바</p> 뒤에 <p id="item">안녕</p>이 들어감.
 
    /* insertBefore */
    /* 기본형 : 부모노드.insertBefore(추가할자식노드, 기준자식노드) */
    list.insertBefore(item, lastList); //결과 : <p id="last">라마바</p> 앞에 <p id="item">안녕</p>이 들어간다.
 
    /* insertData */
    /* 기본형 : 텍스트노드.insertData(추가할위치인덱스, '추가할텍스트') */
    lastList.firstChild.insertData(2,'가나다'); //결과 : <p id="last">라마바</p>가 <p id="last">라마가나다바</p>로 바뀜
</script>
노드의 생성
  • createElement() : 새로운 요소노드를 만든다.
  • createAttribute() : 새로운 속성노드를 만든다. 만약 같은 이름의 속성노드가 이미 존재한다면, 새로운 속성노드로 대체된다.
  • createTextNode() : 새로운 텍스트노드를 만든다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!-- 공통 -->
<div id="exam_wrap">
    <p id="text">텍스트</p>
    <p id="attr">속성</p>
    <p id="empty"></p>
</div>
 
<script>
    const wrap = document.getElementById("exam_wrap"),         
          ogText = document.getElementById("text");
 
    /* createElement */
    const newTxt = document.createElement('p'); 
    newTxt.innerHTML = "새로운 문장";
    wrap.insertBefore(newTxt, ogText); //결과 : <p id="text">텍스트</p> 바로 앞에 <p>새로운 문장<p> 이 추가된다.
 
 
    /* createAttribute */
    const newAttr = document.createAttribute('style'); 
    newAttr.value = "color:red";
    ogText.setAttributeNode(newAttr); //결과 : <p id="text">텍스트</p> 가 <p id="text" style="color:red">텍스트</p> 로 바뀐다.
 
    
    /* createTextnode */
    const newStr = document.createTextnode("새로운 텍스트");
    ogText.appendChild(newStr); //결과 : <p id="text">텍스트</p> 가 <p id="text">텍스트새로운텍스트</p> 로 바뀐다.
</script>
노드의 제거
  • removeChild() : 자식노드 리스트에서 특정 자식노드를 제거한다. 성공적으로 노드가 제거되면 제거된 노드를 반환하고 해당 노드가 가지고 있는 자식노드도 모두 같이 제거된다.
  • removeAttribute() : 속성의 이름을 이용해 특정 속성 노드를 제거한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<!-- 공통 -->
<div>
    <div id="list">
        <p>가나다</p>
        <p id="item" style="color:red">라마바</p>
    </div>
</div>
 
<script>
    const item = document.getElementById("item"),
          list = document.getElementById("list");
 
    /* removeChild */
    /* 기본형 : 부모노드.removeChild(특정자식노드) */
    list.removeChild(item); //결과 : <p id="item" style="color:red">라마바</p> 가 제거된다.
 
    /* removeAttribute */
    /* 기본형 : 노드.removeAttribute(특정속성노드); */
    item.removeAttribute("style"); //결과 : <p id="item" style="color:red">라마바</p> 가 <p id="item">라마바</p> 로 바뀐다.
</script>
노드의 복제
  • cloneNode(자식노드복제여부) : 기존의 존재하는 노드와 똑같은 새노드를 만든다.
  • 자식노드복제여부 : true 값을 넣으면 복제되는 노드의 모든 속성과 자식노드까지 복제되며 false 값을 넣으면 속성노드만 복제하고 자식 노드는 복제하지 않는다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<!-- 공통 -->
<div>
    <div id="list">
        <p>가나다</p>
        <p>라마바</p>
    </div>
</div>
<script>
    const list = document.getElementById("list");
 
    /* true 일 경우 */
    list.appendChild(list.cloneNode(true)); //결과 : list 안에 있는 p까지 모두 복제되어 #list 맨 끝에 들어간다.
 
    /* false 일 경우 (default) */
    list.appendChild(list.cloneNode(false)); //결과 : div#list 만 복제되서 들어갈 뿐 자식요소인 p들은 복제되지 않았다.
</script>
하위 노드 포함 여부
  • 노드.contains(하위노드) : 노드가 하위노드를 가지고 있다면 true를 반환. 그렇지 않으면 false를 반환
1
2
3
4
5
6
7
8
9
10
<div id="myDIV">
    <p>나는 myDIV 야. <span id="mySPAN"><b>span</b></span> 을 가지고 있어.</p>
</div>
 
<script>
const span = document.getElementById("mySPAN");
let answer = document.getElementById("myDIV").contains(span);
 
console.log(answer); //출력결과 : true
</script>

노드의 값 조작

  • 요소 노드는 요소 내에 있는 텍스트 노드를 직접 가지고 있지는 않다. (자식노드로 한다리 건너서 갖고 있다.)
  • 따라서 요소 노드 내에 있는 텍스트 값을 확인하거나 변경하고자할 때는 요소 노드 안에 있는 텍스트노드에 접근해야 한다.
텍스트 노드의 값 변경
  • nodeValue 프로퍼티를 사용해 텍스트 노드의 값을 변경한다.
1
2
3
4
5
6
<div id="text">가나다라마바사</div>
 
<script>
    const text = document.getElementById("text");
    text.firstChild.nodeValue = "텍스트 변경";
</script>
속성 노드의 값 변경
  • 속성노드의 값을 변경할 때에는 setAttribute() 또는 getAttribute() + nodeValue 프로퍼티 조합으로 사용한다.
  • setAttribute() 메서드를 사용할때 변경하고자 하는 속성이 없을 경우 해당 속성을 생성한 후 설정하게 된다.
1
2
3
4
5
6
<div id="text"><p>가나다라마바사<p></div>
 
<script>
    const text = document.getElementById("text");
    text.firstChild.setAttribute("class","new"); //결과 : #text 안에 있는 p 태그에 class="new" 속성이 추가된다.
</script>
요소 노드의 교체
  • replaceChild() 메소드를 사용하면 기존의 요소 노드를 새로운 요소 노드로 교체할 수 있다.
  • 부모노드.replaceChild("새로운자식노드","기존자식노드");
1
2
3
4
5
6
7
8
9
10
<div id="parent">
    <p id="first">가나다라마바사<p>
</div>
<p id="newEl">신규</p>
<script>
    const parent = document.getElementById("parent"),
          first = document.getElementById("first"),
          newEl = document.getElementById("newEl");
    parent.replaceChild(newEl,first); //결과 : #first 노드가 삭제되고 newEl 노드로 교체된다.
</script>
텍스트 노드의 데이터 교체
  • replaceData() 메소드를 사용하면 텍스트 노드의 텍스트 데이터를 바꿀 수 있다.
  • 텍스트노드.replaceData(인덱스번호, 교체할문자수, 새로운데이터);
1
2
3
4
5
<p id="text">가나다라마바사<p>
<script>
    const text = document.getElementById("text").firstChild;
    text.replaceData(2, 3, "안녕하"); //결과 : 가나안녕하바사
</script>