본문 바로가기

공부를 합니다/언어 (Language)

웹브라우저 자바스크립트_6 DOM-4 (Node 객체)

6. DOM

window에 로드된 문서를 제어하기 위한 object model


6.8 Node 객체

DOM의 최상위에 있는 객체. DOM의 모든 객체는 Node 객체를 상속받는다.

주요기능

  • 관계: 각 Node 객체 사이의 관계를 부여
    • Node.childNodes
    • Node.firstChild
    • Node.lastChild
    • Node.nextSibling
    • Node.previousSibling
    • Node.contains()
    • Node.hasChildNodes()
  • 노드의 종류: 각 Node(구성요소)가 어떤 카테고리에 속하는지 알려줌
    • Node.nodeType
    • Node.nodeName
  • 값: Node 객체의 값을 제공
    • Node.nodeValue
    • Node.textContent
  • 자식관리: Node 객체의 자식을 관리(추가 혹은 제거)
    • Node.appendChild()
    • Node.removeChild()

Node 관계 API


Node 사이의 관계를 알 수 있는 API

<body id = "start">
    <ul>
    ...
    </ul>
    <script>
    ...
    </script>
</body>
var start = document.getElementById('start');

Node.firstChild

첫 번째 자식노드

start.firstChild // => #text
  • Text node: 태그 사이에 직접 적힌 text (e.g., <a>html</a>html)
  • <body> 옆의 공백 또는 줄바꿈 등의 문자 때문에 first child가 text로 나오게 된다.
  • <ul>을 바로 붙여서 쓰면 first child가 <ul>로 표시된다.

Node.nextSibling

다음 형제 노드

// body의 첫 자식의 다음 자식을 변수 ul에 담음
start.firstChild.nextSibling // => <ul>
  • <body>의 child node는 바로 옆의 #text
  • #text의 다음 sibling은 <ul> element

Node.parentNode

부모노드

start.firstChilde.parentNode // => <body>
  • #text의 부모 node

Node.childNodes

자식노드들을 유사 배열에 담아서 return

start.childeNodes // => [#text, <ul>, #text, <script>, ...]
  • 유사배열이므로 index notation이나 .length() method를 사용할 수 있다.

Node 종류 API


선택한 node의 종류를 파악하기 위해 사용하는 API

  • 노드의 종류: Node의 종류에 따라 정해진 상수가 존재한다.
    Node name Node number
    ELEMENT_NODE 1
    TEXT_NODE 3
    COMMENT_NODE 8
  • 다음의 코드를 이용해 모두 조회할 수 있다.
    for(var name in Node){
       console.log(name, Node[name]);
    }

Node.nodeType

node의 type(종류)를 return한다.

// <body>의 node type은 1: ELEMENT
start.nodeType // => 1

// body의 first child (줄바꿈 문자)의 node type은 3: TEXT
body.firstChild.nodeType // => 3

상수 대신 해당되는 type 명칭을 사용할 수 있다.

body.nodeType === 1; // => true
body.nodeType === Node.ELEMENT_NODE // => true

Node.nodeName

node의 name(이름)을 return한다.

body.nodeName // => BODY
body.firstChild.nodeName // => #text

재귀함수를 이용한 Node 조회

/* traverse 함수 */
// target: 탐색하는 root element
// callback: element를 탐색할 때 마다 실행하는 함수
function traverse(target, callback){
    if(target.nodeType === 1){
        callback(target);

        // c: target의 자식 elements
        var c = target.childNodes;
        for(var i=0; i<c.length; i++){
            // 현재 target의 각 자식 element를 다시 인자로 전달
            traverse(c[i], callback);       
        }   
    }
}
// traverse 함수의 target을 start로, callback argument를 하단의 함수로 전달.
traverse(document.getElementById('start'), function(elem){
    /* callback 함수로 전달되는 function*/
    // elem 출력
    console.log(elem);

    // elem중 node name이 A인 <a> element만 배경색을 blue로 출력
    if(elem.nodeName === 'A'){
        elem.style.background = blue;
    }
});

노드변경 API


노드를 추가, 제거, 변경하는 API

노드 추가

  • appendChild(child): Node의 마지막 자식으로 주어진 element 추가.
  • insertBefore(newElement, referenceElemenent): appendChilde와 동작 방법은 같지만 두 번째 argument로 전달된 element의 앞에 추가.

노드를 추가하기 위해서는 그 전에 element를 생성해야 한다.

  • document 객체를 이용한다.
  • document.createElement(tagname): element node를 추가.
  • document.createTextNode(data): text node를 추가.
<ul id="target">
    <li>HTML</li>
    <li>CSS</li>
</ul>
/* appendChild를 이용해서 node를 추가하는 함수 */
function callAppendChild(){
    var target = document.getElementById('target');

    // <li> element 생성
    var li = document.createElement('li');
    // 'JavaScript' text element 생성
    var text = document.createTextNode('JavaScript');
    // <li>의 자식노드로 text를 추가
    li.appendChild(text); // => <li>JavaScript</li>
    // <ul> list의 마지막에 <li>JavaScript</li>를 추가
    target.appendChild(li);
}

/* insertBefore를 이용해서 node를 추가하는 함수 */
function callInsertBefore(){
    var target = document.getElementById('target');
    var li = document.createElement('li');
    var text = document.createTextNode('jQuery');
    li.appendChild(text); // => <li>jQuery</li>

    // target의 firstchild (<ul> 옆의 줄바꿈 문자) 앞에 <li>jQuery</li>를 추가
    target.insertBefore(li, target.firstChild);
}

노드 제거

  • removeChild(child): Child element를 삭제
    • 제거하려는 대상의 '부모'node의 method로 실행해야한다.
    • 부모 node와 자식 node를 모두 알아야한다는 번거로움이 있다.
<ul>
    <li>HTML</li>
    <li>CSS</li>
    <li id="target">JavaScript</li>
</ul>
function callRemoveChild(){
    var target = document.getElementById('target');
    // target의 parent node로 이동한 뒤 자식인 target을 제거
    target.parentNode.removeChild(target);
}

노드 변경

  • replaceChild(newchild, oldchild): old child를 new child로 교체
<ul>
    <li>HTML</li>
    <li>CSS</li>
    <li id="target">JavaScript</li>
</ul>
function callReplaceChild(){
    /* <a> element를 생성 */
    var a = document.createElement('a');
    a.setAttribute('href', 'http://opentutorials.org/module/904/6701');
    a.appendChild(document.createTextNode('Web browser JavaScript'));

    var target = document.getElementById('target');
    // target의 first child인 'JavaScript' text를 a로 바꿈
    // <li>JavaScript</li> -> <li><a href = "...">Web browser JavaScript</a></li>
    target.replaceChild(a,target.firstChild);
}

jQuery 노드 변경 API


주로 manipulation 카테고리에 있는 API를 이용한다.

<!-- before -->
<div id = "target">
  content
</div>>

<div id="source">source</div>

노드 추가

  • before, prepend, append, after를 이용한다.
  • 사용하는 API에 따라 노드가 추가되는 위치가 다르다.
before

<tag>
  prepend
  **** content ****
  append
</tag>

after

Example

$('#target').before('<div>before</div>');
$('#target').after('<div>after</div>');
$('#target').prepend('<div>prepend</div>');
$('#target').append('<div>append</div>');
<!-- after -->
<div>before</div>

<div id = "target">
  <div>prepend</div>
  content
  <div>append</div>
</div>>

<div>after</div>

<div id="source">source</div>

노드 제거

  • remove: 선택한 element 자체를 제거.
  • empty: 선택한 element의 text node를 제거.
/* remove */
$('#target').remove();

/* empty */
$('#target').empty();
<!-- after remove -->
id가 target인 <div> element 자체가 제거되기 때문에 아무것도 남지 않음

<!-- after empty -->
<div id = "target">
</div>

<div id="source">source</div>

노드 변경

  • replaceAll: 변경대상을 argument로 전달받아 변경.
  • replaceWith: 변경대상을 먼저 지정한 뒤 변경.
/* replaceAll */
$('<div>replaceAll</div>').replaceAll('#target');

/* replaceWith */
$('#target').replaceWith('<div>replaceWith</div>');
<!-- after replaceAll -->
<div>
  replaceAll
</div>

<div id="source">source</div>

<!-- after replaceWith -->
<div>
  replaceWith
</div>

<div id="source">source</div>

노드 복사

  • clone: 전달받은 객체를 복제.
$('#source').clone().replaceAll('#target');
<div id="source">source</div>

<!-- after clone and replaceAll -->
<div id = "source">
  source
</div>

<div id="source">source</div>

노드 이동

  • 노드를 추가할 때 이용한 API를 이동하는데 쓸 수 있다.
  • 해당 API들의 argument로 이동시킬 element를 전달하면 된다.
$('#target').append($('#source'));
<!-- after append -->
<div id = "target">
  content
  <div id="source">source</div>
</div>

문자열로 노드 제어

좀 더 편리하게 node를 조작하는 방법

<ul id="target">
    <li>HTML</li>
    <li>CSS</li>
</ul>
var target = document.getElementById('target');

innerHTML

선택한 node의 자식 node를 읽어오거나 만들 수 있는 API

// <ul>...</ul> 안의 <li> element들을 경고창에 출력
alert(target.innerHTML);

// <ul>...</ul> 안의 <li> element들을 입력한 값으로 바꿈
target.innerHTML = "<li>JavaScript Core</li><li>BOM</li><li>DOM</li>";
<!-- after -->
<ul id="target">
    <li>JavaScript Core</li>
    <li>BOM</li>
    <li>DOM</li>
</ul>

outerHTML

선택한 node를 '포함'해서 자식 node를 읽어오거나 만들 수 있는 API

// <ul>...</ul> element들을 경고창에 출력
alert(target.outerHTML);

// <ul>...</ul> 안의 <li> element들을 입력한 값으로 바꿈
target.outerHTML = "<ol>JavaScript Core><li>BOM</li><li>DOM</li></ol";
<!-- after -->
<ol>
    <li>JavaScript Core</li>
    <li>BOM</li>
    <li>DOM</li>
</ol>

innerText, outerText

선택한 노드의 HTML 태그를 '제외한' 문자열만을 읽어오거나 HTML 코드를 포함한 '문자열'을 추가하는 API

// <ul>...</ul> 안의 <li> element text들을 경고창에 출력
// HTML CSS만 출력
alert(target.innerText);

// <ul>...</ul> 안의 <li> element를 입력한 'text값으로 바꿈
target.innerText = "<li>JavaScript Core</li><li>BOM</li><li>DOM</li>";
<!-- after -->
<ul id="target">
  "<li>JavaScript Core</li><li>BOM</li><li>DOM</li>"
</ul>

outerText는 선택한 노드를 '포함'해서 innerText처럼 동작한다.

insertAdjacentHTML

보다 정교하게 문자열로 node를 제어할 때 사용.

node를 추가할 위치를 argument로 지정할 수 있다.

/* beforebegin */
target.insertAdjacentHTML('beforebegin','<h1>Client Side</h1>');
/* afterbegin */
target.insertAdjacentHTML('afterbegin','<li>HTML</li>');
/* beforeend */
target.insertAdjacentHTML('beforeend','<li>JavaScript</li>');
/* afterend */
target.insertAdjacentHTML('afterend','<h1>Server Side</h1>');
<!-- before -->
<ul id="target">
  <li>CSS</li>
</ul>

<!-- after -->

<!-- beforebegin -->
<h1>Client Side</h1>
<ul id="target">
  <!-- afterbegin -->
  <li>HTML</li>
  <li>CSS</li>
  <!-- beforeend -->
  <li>JavaScript</li>
</ul>
<!-- afterend -->
<h1>Server Side</h1>