[코드스쿼드] DOM node 생성 및 추가


웹자판기 - DOM & Event 2번째 강의 DOM node 생성 및 추가를 정리한 글 입니다.

목표

  • 다양한 DOM(Document Object Model) APIs를 이해한다
  • element와 text node를 생성해서 화면에 추가할 수 있다



node 탐색 방법

  • node

    • textNode (텍스트도 하나의 node 이다)
    • elementNode
  • 대부분 querySelector 로 div 를 찾고나서 .firstChild 를 수행하면

    • #text 가 출력되는데 이것은 공백을 뜻함 (각 태그 사이의 공백들)
    • 그래서 .firstElementChild 로 해결할 수 있다
    • .nextSibling 이면 공백(#text)이 출력됨
    • .nextElementSibling 으로 해결
  • querySelector 로 찾고 .childNodes 를 해주면 배열형태 로 출력됨

  • 자손 노드 (자식의 자식노드) 까지는 찾을 수 없음

  • nextElementSibling MDN

    • 브라우저 지원범위를 항상 확인해볼 것 (현 크롬 버전은 67, 베타 69)



nodeType의 이해

DOM node는 여러가지 Type이 있다. 어떤 타입이 있는지 이해한다.

var body = document.querySelector("div");
body.nodeType;
/* OUTPUT : 1 (ELEMENT_NODE)*/
var div = document.querySelector("body > div");
body.nodeType;
/* OUTPUT : 1 (ELEMENT_NODE)*/
body.firstChild.nodeType;
/* OUTPUT : 3 (TEXT_NODE)*/

해당 body.firstChild 는 공백(#text) 이 출력되기 때문에 nodeType 이 3 으로 나온것임

nodeType을 이용해서 DOM을 찾아갈 때, Element 인지 Text 인지 알아낼 수 있다



node 생성과 추가

노드를 새롭게 만들고 DOM 트리에 추가하는 방법을 설명하고, 실무에서 많이 사용하는 방법이므로 꼭 실습해본다.

  • 트리구조를 타고 올라간다던가
  • 어떤 노드를 삭제한다던가
  • 특정 노드 전 후로 새로운 노드를 추가한다던가


DOM 탐색 APIs

  • tagName : 엘리먼트의 타입이름을 얻을 수 있다.

    XHTML(또는 XML) 타입에서는 소문자로 출력되며, HTML 에서는 무조건 대문자로 출력된다.

    <span id="born">When I was born...</span>
    
    var span = document.getElementById("born");
    console.log(span.tagName); // "SPAN"
    
  • textContent : 노드와 그 자손의 텍스트 내용을 표시하고, 설정도 가능하다.

    // <span id="born">HE<span>L</span>LO</span>
      
    console.log(span.textContent); // "HELLO"
    console.log(span.innerHTML); // "HE<span>L</span>LO"
    console.log(span.innerText); // "HELLO"
    
    • innerText 와의 차이점
      • textContent 는
      • innerText 는 style 을 인지하고 숨겨진 요소들의 텍스트를 반환하진 않지만 textContent 는 반환함
      • innerText 는 CSS 스타일링을 인지하기 때문에 레이아웃의 변화를 가져올 수 있지만, textContent는 그렇지 않음
      • innerText 는 요소의 자식노드를 지우는 것 뿐만아니라, 텍스트 노드의 모든 자손을 영구적으로 제거함
    • innerHTML 과의 차이점
      • innerHTML 은 HTML을 반환함
      • textContent가 텍스트를 HTML로 파싱하지 않기 때문에 종종 더 좋은 성능을 보여줌
      • textContent는 XSS 를 방지할 수 있음
  • nodeType : elements text comments 처럼 서로 다른 종류의 노드를 구별하는데 사용할 수 있음

  • childNodes : 주어진 요소의 자식 노드 모음 (collection)을 반환함 (NodeList)

    // parg는 <p> 요소 개체 참조
    if (parg.hasChildNodes())
    // 그래서, 먼저 개체가 찼는 지(자식 노드가 있는 지) 검사
     {
       var children = parg.childNodes;
       for (var i = 0; i < children.length; i++) 
       {
       // children[i]로 각 자식에 무언가를 함 
       // 주의: 목록은 유효해(live), 자식 추가나 제거는 목록을 바꿈
       };
     };
    
  • firstChild : 트리에서 노드의 첫 번째 자식이나 null(노드가 자식이 없으면)을 반환함

    <p id="para-01">
      <span>First span</span>
    </p>
      
    <script type="text/javascript">
      var p01 = document.getElementById('para-01');
      alert(p01.firstChild.nodeName)
    </script>
    
  • firstElementChild

    <ul id="foo">
        <li>First  (1)</li>
        <li>Second (2)</li>
        <li>Third  (3)</li>
    </ul>	
    
    var foo = document.getElementById('foo');
    console.log(foo.firstElementChild.textContent); // "First  (1)"
    
  • parentElement : 현재 노드에서 부모 노드를 가리킨다.

    if (node.parentElement) {
        node.parentElement.style.color = "red";
    }
    
  • nextSibling

    부모의 childNodes 목록에서 지정된 노드 바로 다음에 있는 노드를 반환하거나 지정된 노드가 해당 목록의 마지막 노드이면 null을 반환 (#text 데이터를 가져온다는 것을 중점으로 볼 것)

    <div id="div-01">Here is div-01</div>
    <div id="div-02">Here is div-02</div>
      
    <script type="text/javascript">
    var el = document.getElementById('div-01').nextSibling,
        i = 1;
      
    console.log('Siblings of div-01:');
      
    while (el) {
      console.log(i + '. ' + el.nodeName);
      el = el.nextSibling;
      i++;
    }
      
    </script>
      
    /**************************************************
       로드될 때 다음과 같이 콘솔에 기록됩니다. :
      
         Siblings of div-01
      
          1. #text
          2. DIV
          3. #text
          4. SCRIPT
      
    **************************************************/
    
  • nextElementSibling

    <div id="div-01">Here is div-01</div>
    <div id="div-02">Here is div-02</div>
      
    <script type="text/javascript">
      var el = document.getElementById('div-01').nextElementSibling;
      console.log('Siblings of div-01:');
      while (el) {
        console.log(el.nodeName);
        el = el.nextElementSibling;
      }
    </script>
      
    /**************************************************
       로드될 때 다음과 같이 콘솔에 기록됩니다. :
      
        Siblings of div-01:
        DIV
        SCRIPT
      
    **************************************************/
    


DOM 조작 APIs

삭제, 추가, 이동, 교체를 위해 사용하는 DOM API 이다.

  • 추가

    • HTML 문서에 태그들을 추가하는 작업이 쉬운일은 아님
    • 객체화 해서 추가한다
      • 객체화란 ? DOM API 를 이용해서 정해진 메서드들을 통해서 DOM Tree에 맞는 속성값으로 넣는 것
    • 개발자 도구에서 선택한 것은 간단하게 $0 으로 접근할 수 있음
    /* 표준 방법 */
    var div = document.createElement("div");
    var str = document.createTextNode("오늘 하루는 정말 ..좋아");
    div.appendChild(str);
      
    $0.appendChild("div"); /* 여기서 선택한 태그의 마지막 자식으로 추가됨*/
    
  • removeChild() : 자식의 엘리먼트를 삭제하는 문법

    // Get the <ul> element with id="myList"
    var list = document.getElementById("myList");   
    list.removeChild(list.childNodes[0]); // Remove <ul>'s first child node (index 0)
    
  • appendChild() : 한 노드를 특정 부모 노드의 자식 노드 리스트 중 마지막 자식으로 붙임

    // 새로운 단락 요소를 생성하고 문서에 있는 바디 요소의 끝에 붙입니다.
    var p = document.createElement("p");
    document.body.appendChild(p);
    
  • insertBefore()

    <ul id="myList">
      <li>Coffee</li>
      <li>Tea</li>
    </ul>
      
    <p>Click the button to insert an item to the list.</p>
      
    <button onclick="myFunction()">Try it</button>
      
    <script>
    function myFunction() {
        var newItem = document.createElement("LI");
        var textnode = document.createTextNode("Water");
        newItem.appendChild(textnode);
      
        var list = document.getElementById("myList");
        list.insertBefore(newItem, list.childNodes[0]);
    }
    </script>
      
    <!-- 
    Example explained:
    First create a LI node,
    then create a Text node,
    then append the Text node to the LI node.
    Finally insert the LI node before the first child node in the list.
    -->
    
    • nextSibling 를 통해서 삽입하는 경우도 있음

      <div id="parentElement">
        <span id="childElement">foo bar</span>
      </div>
          
      <script>
      // Create a new, plain <span> element
      var sp1 = document.createElement("span");
          
      // Get a reference to the element, before we want to insert the element
      var sp2 = document.getElementById("childElement");
      // Get a reference to the parent element
      var parentDiv = sp2.parentNode;
          
      // Insert the new element into the DOM before sp2
      parentDiv.insertBefore(sp1, sp2);
      </script>
      
      parentDiv.insertBefore(sp1, sp2.nextSibling);
      
  • cloneNode()

    var dupNode = node.cloneNode(deep);
    
    • node : 복제되어야 할 node
    • dupNode : 복제된 새로운 node
    • deep
      • true : 해당 node의 childern 까지 복사
      • false : 해당 node만 복사
  • replaceChild()

    replaceNode = parentNode.replaceChild(newChild, oldChild);
    
    • replaceNode 는 교체된 노드로서, oldChild 와 동일한 노드이다.
    • newChild 는 oldChild를 교체할 새로운 노드이다. (만약 이미 DOM 안에 존재한다면 가장 먼저 제거됨?)
    • oldChild 는 이미 존재하는, 교체될 자식 노드이다.
    // <div>
    //  <span id="childSpan">foo bar</span>
    // </div>
      
    // 텅빈 요소 노드를 하나 생성합니다.
    // ID도, 속성도, 컨텐츠도 없습니다.
    var sp1 = document.createElement("span");
      
    // 'newSpan'이란 id 속성을 부여합니다.
    sp1.id = "newSpan";
      
    // 새로운 요소를 위한 컨텐츠를 생성합니다.
    var sp1_content = document.createTextNode("new replacement span element.");
      
    // 컨텐츠를 생성한 요소에 붙입니다.
    sp1.appendChild(sp1_content);
      
    // DOM에 존재하던, 교체되야할 노드를 참조합니다.
    var sp2 = document.getElementById("childSpan");
    var parentDiv = sp2.parentNode;
      
    // 이미 존재하던 sp2 노드를 새로운 span 요소인 sp1으로 교체합니다.
    parentDiv.replaceChild(sp1, sp2);
      
    // 결과:
    // <div>
    //   <span id="newSpan">new replacement span element.</span>
    // </div>
    





© 2018. by HYEON

Powered by HYEON