Language/Javascript

[Javascript] 자바스크립트 문서 객체 모델 - 노드

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

노드(node)란?

  • HTML 문서 객체 모델(DOM, Document Object Model)은 노드라고 불리는 계층적 단위에 정보를 저장하고 있는데, HTML DOM은 이러한 노드들을 정의하고 그들 사이의 관계를 설명해 주는 역할을 한다.
  • HTML 문서의 정보는 노드들의 집합이며 노드 간의 관계를 보여주는 노드 트리(node tree)라고 불리는 계층적 구조에 저장되는데, 노드 트리는 노드들의 집합이며 노드 간의 관계를 보여준다.
  • 노드 트리는 최상위 레벨인 루트 노드(root node)로부터 시작하여 가장 낮은 레벨인 텍스트 노드까지 뻗어 내려가는데, 자바스크립트에서는 HTML DOM을 이용하여 노드 트리에 포함된 모든 노드에 접근할 수 있다.

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

 

노드의 종류

  • W3C HTML DOM 표준에 따르면, HTML 문서의 모든 것은 노드다.
    • 문서 노드(document node) : HTML 문서 전체를 나타내는 노드
    • 요소 노드(element node) : 모든 HTML 요소는 요소 노드이며, 속성 노드를 가질 수 있는 유일한 노드
    • 속성 노드(attribute node) : 모든 HTML 요소의 속성은 속성 노드이며, 요소 노드에 관한 정보를 가지고 있지만 해당 요소 노드의 자식 노드(child node)에는 포함되지 않음.
    • 텍스트 노드(text node) : HTML 문서의 모든 텍스트는 텍스트 노드
    • 주석 노드(comment node) : HTML 문서의 모든 주석은 주석 노드

 

노드 간의 관계

  • 노드 트리의 가장 상위에는 단 하나의 루트 노드(root node)가 존재하며, 루트 노드를 제외한 모든 노드는 단 하나의 부모 노드(parent node)만을 가진다.
  • 모든 요소 노드는 자식 노드(child node)를 가질 수 있으며, 형제 노드(sibling node)란 같은 부모 노드를 가지는 모든 노드를 가리킨다.
  • 조상 노드(ancestor node)란 부모 노드를 포함해 계층적으로 현재 노드보다 상위에 존재하는 모든 노드를 가리키며, 자손 노드(descendant node)란 자식 노드를 포함해 계층적으로 현재 노드보다 하위에 존재하는 모든 노드를 가리킨다.

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

 

노드로의 접근

getElementsByTagName() 메소드를 이용하는 방법

  • getElementsByTagName() 메소드는 HTML 특정 태그 이름을 가지는 모든 요소를 노드 리스트의 형태로 반환하므로 이 메소드가 반환하는 노드 리스트를 이용하면 원하는 노드에 접근할 수 있다.
// 모든 <li> 요소선택
var selectedItem = document.getElementsByTagName("li");

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

노드 간의 관계를 이용하여 접근하는 방법

  • HTML DOM에서 노드 간의 관계는 다음과 같은 프로퍼티로 정의되는데, 아래와 같은 프로퍼티를 이용하여 원하는 노드에 손쉽게 접근할 수 있다.
    • parentNode : 부모 노드
    • childNodes : 자식 노드 리스트
    • firstChild : 첫 번째 자식 노드
    • lastChild : 마지막 자식 노드
    • nextSibling : 다음 형제 노드
    • previousSibling : 이전 형제 노드

 

노드에 대한 정보

  • 노드에 대한 정보는 다음과 같은 프로퍼티를 통해 접근할 수 있으며, 이 프로퍼티들은 특별히 다른 인터페이스를 이용하지 않고도 해당 노드의 정보에 직접 접근할 수 있는 방법을 제공한다.

nodeName

  • nodeName 프로퍼티는 노드 고유의 이름을 저장하므로 수정할 수 없는 읽기 전용 프로퍼티며, 요소 노드의 nodeName 프로퍼티는 언제나 해당 HTML 요소의 태그 이름을 대문자로 저장한다.

// HTML 문서의 모든 자식 노드 중에서 두 번째 노드의 이름을 선택
// HTML 문서의 첫 번째 자식 노드는 <!DOCTYPE html>, 두 번째 자식 노드는 <html>
document.getElementById("document").innerHTML = document.childNodes[1].nodeName;                    // HTML 

// html 노드의 모든 자식 노드 중에서 첫 번째 노드의 이름을 선택
// <html>노드의 첫 번째 자식 노드는 <head>
document.getElementById("html").innerHTML = document.childNodes[1].childNodes[0].nodeName;      // HEAD

nodeValue

  • nodeValue 프로퍼티는 노드의 값을 저장한다.
  • innerHTML 프로퍼티를 사용하여 손쉽게 HTML 요소의 내용(content)에 접근하거나 변경할 수 있지만, innerHTML 프로퍼티 대신에 firstChild.nodeValue를 사용해도 같은 결과를 얻을 수 있다.

// 아이디가 heading인 요소의 첫 번째 자식 노드의 노드값을 선택
var headingText = document.getElementById("heading").firstChild.nodeValue;

document.getElementById("text1").innerHTML = headingText;
document.getElementById("text1").firstChild.nodeValue = headingText;

nodeType

  • nodeType 프로퍼티는 노드 고유의 타입을 저장하므로, 수정할 수 없는 읽기 전용 프로퍼티다.

// 아이디가 heading인 요소의 첫 번째 자식 노드의 타입을 선택
var headingType = document.getElementById("heading").firstChild.nodeType;

document.getElementById("head").innerHTML = headingType;           // 3
document.getElementById("document").innerHTML = document.nodeType; // 9

 

빈 텍스트 노드의 처리

  • 현재 대부분의 주요 웹 브라우저는 모두 W3C DOM 모델을 지원하지만 그 처리 방식에 있어 약간씩의 차이가 있다.
  • 예를 들어, 띄어쓰기와 줄 바꿈을 파이어폭스나 기타 브라우저들에서는 텍스트 노드(text node)로 취급하지만 익스플로러는 텍스트 노드로 취급하지 않으므로, 자식 노드나 형제 노드를 이용하여 원하는 노드에 접근하려면 브라우저 간에 차이가 발생한다.
  • 브라우저간의 차이를 없애는 가장 손쉬운 방법은 nodeType 프로퍼티를 사용하여 선택된 요소의 타입을 검사하는 것이다.
/* 마지막 자식 노드 찾은 후 찾은 노드 타입이 요소 노드가 아니면 그 앞의 노드를 다시 검사 */
var lastNode;

function findLastChild(parentNode) {
	lastNode = parentNode.lastChild;
	while (lastNode.nodeType != 1) {
		lastNode = lastNode.previousSibling;
	}
}

function printLastChild() {
	var parentNode = document.getElementById("parentNode");
	findLastChild(parentNode);
	document.getElementById("nodename").innerHTML = lastNode.nodeName;
}

 

노드 리스트(node list)

  • 노드 리스트는 getElementsByTagName() 메소드나 childNodes 프로퍼티의 값으로 반환되는 객체로, HTML 문서와 같은 순서로 문서 내의 모든 노드를 리스트 형태로 저장하고 있다.
  • HTML DOM에서 각 요소 노드 다음에는 별도의 텍스트 노드가 존재하며, 리스트의 각 노드는 0부터 시작하는 인덱스를 이용하여 접근할 수 있다.

/* 각 요소 노드 다음에 또 다른 텍스트 노드가 존재할 경우 */
<ul id="list">ul 요소 다음의 텍스트
	<li>첫 번째 아이템이에요!</li>첫 번째 li 요소 다음의 텍스트
	<li>두 번째 아이템이에요!</li>두 번째 li 요소 다음의 텍스트
	<li>세 번째 아이템이에요!</li>세 번째 li 요소 다음의 텍스트
</ul>

<script>
    // 아이디가 list인 요소의 모든 자식 노드들을 선택
    var listItems = document.getElementById("list").childNodes;
	
    // 자식 노드들 중 첫번째 노드값 출력 - 'ul 요소 다음의 텍스트'
    document.write(listItems[0].nodeValue);
	
    // 자식 노드들 중 두번째 노드의 자식노드 중 첫번째 노드값 출력 - '첫 번째 아이템이에요!'
    document.write(listItems[1].firstChild.nodeValue);
   
    // 자식 노드들 중 세번째 노드값 출력 - '첫 번째 li 요소 다음의 텍스트'
    document.write(listItems[2].nodeValue);
</script>
  • 노드 리스트 객체는 리스트에 노드를 추가하거나 삭제되면 자신의 상태 정보를 스스로 갱신하므로, length 프로퍼티 값은 언제나 노드 리스트가 저장하고 있는 노드들의 총 개수를 나타낸다
// 모든 <li> 요소들을 선택
var listItems = document.getElementsByTagName("li"); 

// 모든 자식 노드들의 개수 반환
document.getElementById("text").innerHTML = 
"이 노드 리스트의 길이는 " + listItems.length + "개 입니다.<br>"; 

// 모든 자식 노드들의 글자색을 변경
function changeTextColor() {
    for (var i = 0; i < listItems.length; i++) {
        listItems[i].style.color = "orange";               
    }
}

 

노드의 추가

appendChild() 메소드

  • appendChild() 메소드는 새로운 노드를 해당 노드의 자식 노드 리스트(child node list)의 맨 마지막에 추가한다.
function appendNode() {
    // 아이디가 list인 요소 선택
    var parent = document.getElementById("list");  
    // 아이디가 item인 요소 선택
    var newItem = document.getElementById("item"); 
    // 해당 요소의 맨 마지막 자식 노드로 추가
    parent.appendChild(newItem);                   
}

insertBefore() 메소드

  • insertBefore() 메소드는 새로운 노드를 특정 자식 노드 바로 앞에 추가한다.
  • 기준 자식 노드에 null 값을 전달하면 새로운 노드는 자식 노드 리스트의 맨 마지막 노드로 추가되므로, appendChild() 메소드와 완전히 같은 동작을 한다.
    • 새로운 자식 노드 : 자식 노드 리스트(child node list)에 새롭게 추가할 자식 노드를 전달한다.
    • 기준 자식 노드 : 새로운 노드를 삽입할 때 기준이 되는 노드로, 이 노드 바로 앞에 새로운 노드가 추가된다.
부모노드.insertBefore(새로운자식노드, 기준자식노드);
function appendNode() {
    // 아이디가 list인 요소를 선택
    var parent = document.getElementById("list"); 
    // 아이디가 criteria인 요소를 선택
    var criteriaItem = document.getElementById("criteria"); 
    // 아이디가 item인 요소를 선택
    var newItem = document.getElementById("item");          
    // 해당 노드를 기준이 되는 자식 노드의 바로 앞에 추가
    parent.insertBefore(newItem, criteriaItem); 
}

insertData() 메소드

  • insertData() 메소드는 텍스트 노드의 텍스트 데이터에 새로운 텍스트를 추가한다.
    • 오프셋(offset) : 오프셋 값은 0부터 시작하며, 기존 텍스트 데이터의 몇 번째 위치부터 추가할지를 전달한다.
    • 새로운 데이터 : 새로이 삽입할 텍스트 데이터를 전달한다.
텍스트노드.insertData(오프셋, 새로운데이터);
// 아이디가 text인 요소의 텍스트 노드를 선택
var text = document.getElementById("text").firstChild; 

function appendText() {
    // 텍스트 노드의 6번째 문자부터 나른한이란 텍스트를 추가
    text.insertData(6, " 나른한 "); 
}

 

노드의 생성

요소 노드의 생성

  • createElement() 메소드를 사용하여 새로운 요소 노드를 만들 수 있다.
function createNode() {
    // 기준이 되는 요소로 아이디가 text인 요소를 선택
    var criteriaNode = document.getElementById("text"); 
    // 새로운 <p> 요소를 생성
    var newNode = document.createElement("p");          
    newNode.innerHTML = "새로운 단락입니다.";
    // 새로운 요소를 기준이 되는 요소 바로 앞에 추가
    document.body.insertBefore(newNode, criteriaNode); 
}

속성 노드의 생성

  • createAttribute() 메소드를 사용하여 새로운 속성 노드를 만들 수 있다.
  • 만약 같은 이름의 속성 노드가 이미 존재하면 기존의 속성 노드는 새로운 속성 노드로 대체되고, 이미 존재하는 요소 노드에 속성 노드를 생성하고자 할 때에는 setAttribute() 메소드를 사용할 수 있다.
function createNode() {
    // 아이디가 text인 요소를 선택
    var text = document.getElementById("text");           
    // 새로운 style 속성 노드를 생성
    var newAttribute = document.createAttribute("style"); 
    newAttribute.value = "color:red";
    // 해당 요소의 속성 노드로 추가
    text.setAttributeNode(newAttribute);                  
}

텍스트 노드의 생성

  • createTextNode() 메소드를 사용하여 새로운 텍스트 노드를 만들 수 있다.
function createNode() {
    // 아이디가 text인 요소를 선택
    var elementNode = document.getElementById("text");           
    // 새로운 텍스트 노드를 생성
    var newText = document.createTextNode("새로운 텍스트에요!"); 
    // 해당 요소의 자식 노드로 추가
    elementNode.appendChild(newText);                            
}

 

노드의 제거

removeChild() 메소드

  • removeChild() 메소드는 자식 노드 리스트에서 특정 자식 노드를 제거한다.
  • 성공적으로 노드가 제거되면 제거된 노드를 반환하고, 노드가 제거될 때에는 제거되는 노드의 모든 자식 노드들도 다 같이 제거된다.
// 아이디가 "list"인 요소를 선택
var parent = document.getElementById("list");      
// 아이디가 "item"인 요소를 선택
var removedItem = document.getElementById("item"); 
// 지정된 요소를 삭제
parent.removeChild(removedItem);

removeAttribute() 메소드

  • removeAttribute() 메소드는 속성 이름을 이용하여 특정 속성 노드를 제거한다.
// 아이디가 text인 요소를 선택
var text = document.getElementById("text"); 
// 해당 요소의 style 속성을 제거
text.removeAttribute("style");

 

노드의 복제

cloneNode() 메소드

  • cloneNode() 메소드는 기존의 존재하는 노드와 똑같은 새로운 노드를 생성하여 반환한다.
  • 자식 노드 복제 여부 : 전달된 값이 true이면 복제되는 노드의 모든 속성 노드와 자식 노드도 같이 복제하며, false이면 속성 노드만 복제하고 자식 노드는 복제하지 않는다.
복제할노드.cloneNode(자식노드복제여부);
function cloneElement() {
    // 아이디가 "list"인 요소를 선택
    var parent = document.getElementById("list");     
    // 아이디가 "item"인 요소를 선택
    var originItem = document.getElementById("item"); 
    // 해당 노드를 복제하여 리스트의 맨 마지막에 추가
    parent.appendChild(originItem.cloneNode(true));   
}

 

노드의 조작

요소 노드의 텍스트

  • 요소 노드는 자신이 직접 텍스트값을 가지지는 않고 요소 노드의 텍스트는 요소 노드의 자식 노드인 텍스트 노드에 저장되므로, 요소 노드의 텍스트 값을 확인하거나 변경하고자 할 때는 요소 노드에 포함된 텍스트 노드에 접근해야 한다.

텍스트 노드의 값 변경

  • nodeValue 프로퍼티를 사용하여 텍스트 노드의 값을 변경할 수 있다.
// 아이디가 text인 요소를 선택
var para = document.getElementById("text"); 

function changeText() {
    para.firstChild.nodeValue = "텍스트 변경 완료!";
}

속성 노드의 값 변경

  • 속성 노드는 nodeValue 프로퍼티뿐만 아니라 setAttribute() 메소드를 사용하여 값을 변경할 수 있다.
  • setAttribute() 메소드는 속성값을 변경하려는 속성이 존재하지 않으면, 먼저 해당 속성을 생성한 후에 속성값을 설정한다.
var para;

function changeAttribute() {
    // 모든 <p> 요소중에서 첫 번째 요소에 클래스 속성값으로 para를 설정
    // 클래스가 설정되면 해당 클래스에 설정되어 있던 스타일이 자동으로 적용
    document.getElementsByTagName("p")[0].setAttribute("class", "para");
}

요소 노드의 교체

  • replaceChild() 메소드를 사용하면 기존의 요소 노드를 새로운 요소 노드로 교체할 수 있다.
    • 새로운 자식 노드 : 자식 노드 리스트에 새롭게 추가할 요소 노드를 전달한다.
    • 기존 자식 노드 : 자식 노드 리스트에서 제거할 요소 노드를 전달한다.
교체할노드 = 부모노드.replaceChild(새로운자식노드, 기존자식노드);
/* 자식 노드 중 첫번째 요소 삭제, 그 대신에 세번째 요소를 첫번째 요소 자리에 삽입 */
var parent = document.getElementById("parent"); // 부모 노드를 선택
var first = document.getElementById("first");
var third = document.getElementById("third");

function changeNode() {
    // first 요소를 삭제하고, 그 대신 third 요소를 삽입
    parent.replaceChild(third, first);          
}

텍스트 노드의 데이터 교체

  • replaceData() 메소드를 사용하면 텍스트 노드의 텍스트 데이터를 바꿀 수 있다.
    • 오프셋(offset) : 오프셋 값은 0부터 시작하며, 기존 텍스트 데이터의 몇 번째 문자부터 교체할지를 전달한다.
    • 교체할 문자 수 : 기존 텍스트 노드의 데이터로부터 교체할 총 문자 수를 전달한다.
    • 새로운 데이터 : 새로이 삽입할 텍스트 데이터를 전달한다.
텍스트노드.replaceData(오프셋, 교체할문자수, 새로운데이터);
// 아이디가 text인 요소의 텍스트 노드를 선택
var text = document.getElementById("text").firstChild; 

function changeText() {
    // 텍스트 노드의 7번째 문자부터 4개의 문자를 저녁 7로 교체
    text.replaceData(7, 4, "저녁 7"); 
}

 

Reference

반응형