멋쟁이v의 개발일지

[Javascript] DOM(Document Object Model) 본문

0년차/Javascript

[Javascript] DOM(Document Object Model)

멋쟁이v 2023. 5. 14. 14:48
728x90
320x100

[목차]


01. DOM

  • DOM이란?
    💡
    문서 객체 모델

    ➡️ html구조가 저장된 객체이며, window 객체의 하위에 있다.

    👉🏻
    ➡️ HTML 문서의 계층적 구조와 정보를 표현하여 이를 제어할 수 있는 API

    ➡️ 브라우저의 렌더링 엔진은 웹 문서를 로드한 후 파싱하여 웹 문서를 브라우저가 이해할 수 있는 구조로 구성하여 메모리에 적재하는데 이를 DOM이라 한다.

    ➡️ 모든 요소와 요소의 어트리뷰트, 텍스트를 각각의 객체로 만들고 이 객체를 부자 관계로 표현할 수 있는 트리 구조로 구성한 것

    ➡️ 최상위 root 노드는 document 객체를 가르킨다.

    ➡️ window.document 혹은 document로 참조

  • DOM 노드 타입

    ➡️ 문서노드

    👉🏻
    DOM 트리의 최상위에 존재하는 루트 노드 document 객체를 가리킨다.

    document 객체 : 브라우저가 렌더링한 HTML 문서 전체를 가리키는 객체이다.

    window.document 혹은 document로 참조

    요소, 어트리뷰트(속성), 텍스트노드 접근시 문서 노드를 통해야함.

    ➡️ 요소노드

    👉🏻
    HTML 요소를 가리키는 객체

    부자관계를 가짐(부모노드와 연결)

    문서의 구조를 표현

    ➡️ 어트리뷰트 노드

    👉🏻
    HTML 요소의 속성을 가리키는 객체

    어트리뷰트 노드는 부모노드와 연결되어 있지 않음.

    요소의 속성을 변경시 요소노드에 먼저 접근

    ➡️ 텍스트 노드

    👉🏻
    HTML 요소의 텍스트를 가리키는 객체

    요소노드는 문서의 구조표현 VS 텍스트노드는 문서의 정보 표현

    ➡️ 예시

    👉🏻
    <div class=”title”>hello</div>

    요소노드 : div, 어트리뷰트 노드 : class, 텍스트 노드 : hello

02. DOM 취득

  • 요소노드 취득

    ➡️ document.getElementById(id)

    👉🏻
    id 어트리뷰트 값으로 요소 노드를 한 개 선택한다. 복수개 일 경우 첫번째 요소 반환

    HTMLElement를 상속받은 객체 반환, 요소노드 없을 시 null 반환

    ➡️ document.querySeletor(css선택자)

    👉🏻
    css선택자를 사용하여 요소 노드를 한 개 선택한다. 복수개 일 경우 첫번째 요소만 반환

    HTMLElement를 상속받은 객체 반환, 요소노드 없을 시 null 반환

    ➡️ document.getElementByClassName(class이름)

    👉🏻
    class 어트리뷰트 값으로 요소 노드를 모두 선택한다. 공백으로 구분하여 여러 개의 class를 지정 가능

    HTMLCollection (live) 반환, 요소노드 없을 시 빈 HTMLCollection 반환 (HTMLCollection은 변경 시 실시간으로 반영된다.)

    ➡️ document.getElementByTagName(tag이름)

    👉🏻
    태그명으로 요소 노드를 모두 취득한다.

    HTMLCollection (live) 반환, 요소노드 없을 시 빈 HTMLCollection 반환

    ➡️ document.querySelectorAll(css선택자)

    👉🏻
    지정된 css선택자를 사용하여 요소노드를 모두 취득

    NodeList (non-live) 반환, 요소노드 없을 시 빈 NodeList 반환

    ➡️ document.qeuerySelector(css선택자).matches(css선택자)

    👉🏻
    선택한 요소가 다른 css 선택자문법의 요소로 취득할 수 있는지 확인

  • [코드예제] 요소노드 취득
    	<!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <link rel="icon" href="data:,">
        <title>문서객체(DOM)</title>
    </head>
    <body>
        <h1>요소노드 취득</h1>
    	  - HTML의 구조나 내용 또는 스타일 등을 동적으로 조작하려면 먼저 요소 노드를 취득<br>
        
        <h2>id를 이용한 요소노드 취득</h2>
        - document.getElementById(요소 id);<br>
        - 반드시 문서노드를 통해 호출<br>
        
        <ul>
          <li id="ks301">한국스마트정보교육원 강의실301</li>
          <li id="ks302">한국스마트정보교육원 강의실302</li>
        </ul>
    
        <script>
    
          const $ks301Ele = document.getElementById('ks301');
          console.log({$ks301Ele});
          $ks301Ele.style.color = 'red';
          const $ks303Ele = document.getElementById('ks303');
          console.log($ks303Ele, '요소노드가 없을 시 반환값');
          
        </script>
    
    		<!-- ---------------------------------------------------- -->
    
        <h2>태그 이름을 이용한 요소노드 취득</h2>
        - document.getElementsByTagName(태그이름);<br>
        - 모든 요소를 취득시에는 인수로 '*'를 전달<br>
        - 반드시 문서노드를 통해 호출<br>
        - HTMLCollection 객체에 담겨 반환<br>
    
        <ul>
          <li>ksmart301</li>
          <li>ksmart302</li>
          <li>ksmart교직원실</li>
        </ul>
    
        <script>
          // 문서가 가진 전체 태그 취득
          const $allTagEles = document.getElementsByTagName('*');
          console.log($allTagEles);
    
          // 문서가 가진 li 태그 취득
          const $liTags = document.getElementsByTagName('li');
          console.log($liTags);
    
    			// HTMLCollection 실시간 반영 문제점 발생
          for(let i=0; i<$liTags.length; i+=1){
            console.log($liTags[i]);
          }
          console.log($liTags.item(1), 'HTMLCollection.item(인덱스)');
    
          // 문제점 해결.
    			// HTMLCollection은 유사배열이므로 배열로 변환 가능
          [...$liTags].forEach(function (item, idx) {
            console.log(item, '배열로 형변환하여 forEach를 이용한 li태그')
          });
    
          // 문서가 가진 img 태그 취득
          const $imgEle = document.getElementsByTagName('img');
          console.log($imgEle, '일치하는 태그가 없을시 반환값');
          
        </script>
    
    			<!-- ---------------------------------------------------- -->
    
        <h2>class를 이용한 요소노드 취득</h2>
        - document.getElementsByClassName(클래스이름);<br>
        - 반드시 문서노드를 통해 호출<br>
        - HTMLCollection 객체에 담겨 반환<br>
        
        <ul>
          <li class="ksmart">강의실 301호</li>
          <li class="ksmart">강의실 302호</li>
          <li class="ksmart">교직원실</li>
        </ul>
    
        <script>
    
          const $ksmartEles = document.getElementsByClassName('ksmart');
          console.log($ksmartEles, '클래스 이름으로 취득');
    
          /* 문제점 HTMLCollection이 live한 객체이므로 실시간 갱신되어
    		     ksmart 클래스의 값을 가진 모든 요소의 클래스값이
    		     변경되지 않는 이슈
    		     $ksmartEles = [li, li, li] -> [li, li] (HTMLCollection의 갯수가 달라짐)
          for(let i=0; i<$ksmartEles.length; i+=1) {
            $ksmartEles[i].className = 'ks';
          }
          */
    
          /**
           * HTMLCollection을 배열로 변환하여 문제점 해결
           */
          // 스프레드 : 새로운 배열에 주소값만 가져온다.
          [...$ksmartEles].forEach(function (item, idx) {
            item.className = 'ks';
          });
    
        </script>
    
    		<!-- ---------------------------------------------------- -->
    
        <h2>CSS 선택자를 이용한 요소노드 취득</h2>
        <h3>querySelector</h3>
        - document.querySelector(css선택자);<br>
        - 인수로 전달된 css 선택자를 만족시키는 하나의 요소 노드를 탐색하여 반환<br>
        - 인수로 전달된 css 선택자를 만족시키는 요소 노드가 여러 개인 경우 첫번째 요소 반환<br>
        - 인수로 전달된 css 선택자를 만족시키는 요소 노드가 존재하지 않는 경우 null 반환<br>
        - 인수로 전달된 css 선택자가 문법에 맞지 않은 경우 DOMException 에러 발생<br>
        <ul>
          <li class="ksmart301">ksmart301-0</li>
          <li class="ksmart301">ksmart301-1</li>
          <li class="ksmart302">ksmart302</li>
        </ul>
        <script>
          /**
           * css 선택자
           *  1) * : 모두 선택
           *  2) 태그선택자 : 태그이름
           *  3) 아이디, 클래스 선택자 : id(#), class(.) (ex: <label id="exLabel" class="exLabel">)
           *  4) 속성선택자 : 태그[속성=값] : 해당 태그의 속성값 일치하는 요소 선택 (ex: label[class="exLabel"])
           *  5) 하위(후손)선택자 : 첫번째 태그의 자식요소 중 두번째 태그 선택 (ex: div label)
           *  6) 자식 선택자(>) : 첫번째 태그의 자식요소 중 두번째 태그 선택 (ex : div > label)
           *  7) 인접 형제 선택자(+) : 첫번째 태그의 형제요소 다음에 위치한 인접한 두번째 태그 선택
           *  8) 일반 형제 선택자(~) : 첫번째 태그의 형제요소 다음에 위치한 두번째 태그 다중 선택
           */
    
          const $302Ele = document.querySelector('.ksmart302');
          console.log($302Ele, `\n`, {$302Ele});
    
          // class 이름 중복시 querySelector
          const $301Ele = document.querySelector('.ksmart301');
          console.log($301Ele, `\n`, {$301Ele});
    
          const $303Ele = document.querySelector('.ksmart303');
          console.log($303Ele, '\n', 'css선택자에 일치하는 요소가 없을때 반환값');
    
        </script>
    
    		<!-- ---------------------------------------------------- -->
    
        <h3>querySelectorAll</h3>
        - document.querySelectorAll(css선택자);<br>
        - 인수로 전달된 css 선택자를 만족시키는 요소 노드가 존재하지 않는 경우 빈 NodeList 반환<br>
        - 인수로 전달된 css 선택자가 문법에 맞지 않은 경우 DOMException 에러 발생<br>
        <ul>
          <li class="ksmart-course">한국스마트정보교육원IT과정</li>
          <li class="ksmart-course">ksIT과정</li>
          <li class="ksmart-course">ksmartIT과정</li>
        </ul>
        <script>
    
          const $allTags = document.querySelectorAll('*');
          console.log($allTags);
    
          const $ksCourseEles = document.querySelectorAll('.ksmart-course');
          console.log($ksCourseEles);
          /*
          for(let i=0; i<$ksCourseEles; i+=1){
            $ksCourseEles[i].className = 'ks-course';
          }
          */
          [...$ksCourseEles].forEach(function (item, idx) {
            console.log(item, 'NodeList를 배열로 변환하여 forEach 구문 실행')
          });
          console.log([...$ksCourseEles]);
    
          const $videoEles = document.querySelectorAll('video');
          console.log($videoEles, '찾으려는 요소가 없을 시 반환값');
    
          // DOMException 발생 : css선택자 구문에 일치하지 않으면
          // document.querySelectorAll('123>w');
          
        </script>
    
    		<!-- ---------------------------------------------------- -->
    
        <h2>특정 요소노드 취득 여부 확인</h2>
        <h3>matches</h3>
        - document.querySelector(css선택자).matches(css선택자);<br>
        - 선택한 요소가 다른 css 선택자문법의 요소로 취득할 수 있는지 확인<br>
        - li.ksmart47 == li[class="ksmart47"]
        <ul id="ksmart">
          <li class="ksmart46">46기</li>
          <li class="ksmart47">47기</li>
          <li class="ksmart48">48기</li>
        </ul>
        <script>
    
          const $ksmart47Ele = document.querySelector('li.ksmart47');
          let result = $ksmart47Ele.matches('li');
          console.log(result);
          result = $ksmart47Ele.matches('li.ksmart46');
          console.log(result);
          result = $ksmart47Ele.matches('li[class="ksmart47"]');
          console.log(result);
    
        </script>
    </body>
    </html>

03. DOM 탐색

💡
요소노드를 취득한 다음, 취득한 요소노드를 기점으로 부모, 형제, 자식 노드 탐색
  • 요소노드 탐색

    ➡️ 부모노드 탐색

    • parentNode
    • closest(’css선택자’) : 탐색한 노드를 기준으로 css선택자와 일치하는 가장 가까운 조상을 탐색, 없을 경우 null 반환

    ➡️ 자식노드 탐색

    • childNodes : 텍스트 요소 포함한 모든 자식요소 반환, NodeList
    • firstChlid, lastChild : 텍스트 요소 포함한 모든 자식 요소 반환
    • children : 자식요소 중에서 Element type 요소만을 반환, HTMLCollection
    • firstElementChild, lastElementChild : 자식요소 중에서 Element type 요소만을 반환, HTMLCollection
    • 자식노드 존재여부 확인 : hasChildNodes() - true(존재), false(존재x) 반환

    ➡️ 형제노드 탐색

    • previousSibling, nextSibling : 텍스트 요소 포함한 모든 형제요소 반환
    • previousElementSibling, nextElementSibling : 형제 노드 중에서 Element type 요소만을 반환, 형제 노드 없을 시 null 반환

  • [코드예제] 요소노드 탐색
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <link rel="icon" href="data:,">
        <title>DOM 노드 탐색</title>
    </head>
    <body>
        <h1>DOM 노드탐색</h1>
        - 요소노드를 취득한 다음, 취득한 요소노드를 기점으로 부모, 형제, 자식 노드 탐색
        <script>
    
          const $h2Ele = document.querySelector('h2');
          console.log($h2Ele);
          const $h2Eles = document.getElementsByTagName('h2');
          console.log($h2Eles);
    
        </script>
        
        <h2>자식노드 탐색</h2>
        - 자식노드를 탐색하기위해서 탐색 프로퍼티 사용<br>
        - childNodes: 자식노드를 모두 탐색 후 NodeList에 담아 반환(요소노드뿐만 아니라 텍스트노드포함) <br>
        - children: 자식중 요소노드만 탐색 후 HTMLCollection에 담아 반환<br>
        - firstChild: 첫번째 자식 노드 반환(요소노드, 텍스트노드)<br>
        - lastChild: 마지막 자식 노드 반환(요소노드, 텍스트노드)<br>
        - firstElementChild: 첫번째 자식 요소 노드 반환<br>
        - lastElementChild: 마지막 자식 요소 노드 반환<br>
        - querySelector('css선택자') : 탐색한 노드를 기준으로 css선택자와 일치하는 자식노드 반환
                                      선택자가 겹칠 경우 가장 첫번째 노드 반환<br>
        - querySelectorAll('css선택자') : 탐색한 노드를 기준으로 css선택자와 일치하는 자식노드들 반환<br>
        
        <ul id="ksmart">
            <li class="ksmart301">강의실 301호</li>
            <li class="ksmart302">강의실 302호</li>
        </ul>
    
        <script>
    
          const $ulKsmartEle = document.getElementById('ksmart');
          console.log($ulKsmartEle, {$ulKsmartEle});
          console.log($ulKsmartEle.childNodes);
    
          // 취득한 노드에서 첫번째 자식 노드 반환
          const $ulChild = $ulKsmartEle.childNodes;
          console.log($ulChild[0], 'childNodes를 통한 첫번째 요소반환');
    
          // firstChild (텍스트노드, 요소노드 모두 포함)
          console.log($ulKsmartEle.firstChild);
    
          // lastChild (텍스트노드, 요소노드 모두 포함)
          console.log($ulKsmartEle.lastChild);
          console.log($ulChild[$ulChild.length-1], 'childNodes를 통한 마지막 요소반환');
    
          // children : 자식중 요소노드만 탐색 후 HTMLCollection에 담아 변환
          const ulChildren = $ulKsmartEle.children;
          console.log(ulChildren, '텍스트노드 포함하지 않고 요소노드만 HTMLCollection에 담아 변환')
    
          // firstElementChild: 첫번째 자식 요소 노드 반환(요소노드만)
          console.log($ulKsmartEle.firstElementChild);
    
          // lastElementChild: 마지막 자식 요소 노드 반환(요소노드만)
          console.log($ulKsmartEle.lastElementChild);
          const lastChild = $ulKsmartEle.lastElementChild;
          console.log({lastChild});
          console.log(ulChildren[ulChildren.length-1]);
    
          // querySelector()를 이용한 자식노드 탐색
          const $ksmart302Ele = $ulKsmartEle.querySelector('.ksmart302');
          console.log($ksmart302Ele);
    
          // querySelectorAll()를 이용한 자식노드 전체 탐색
          const $ulLiEles = $ulKsmartEle.querySelectorAll('li');
          console.log($ulLiEles);
          
        </script>
    
        <h2>자식 노드 존재 여부 확인</h2>
        - hasChildNodes(): true(존재), false(존재하지않음) 반환 <br>
        - 특정자식 노드 탐색<br>
        - 부모노드 접근 후 자식노드 탐색 <br>
        
        <ul id="ks">
            <li class="ks46">한국스마트정보교육원46기</li>
            <li class="ks47">한국스마트정보교육원47기</li>
        </ul>
    
        <script>
    
          const $ulKsEle = document.getElementById('ks');
          console.log($ulKsEle.hasChildNodes(), '자식노드 존재 여부');
          console.log(($ulKsEle.children.length>0), '자식노드 존재여부 판단');
            
        </script>
    
        <h2>부모노드 탐색</h2>
        - parentNode : 탐색한 노드를 기준으로 부모노드 탐색
        - 최종단의 노드는 텍스트 노드 이므로 부모가 텍스트 노드인 경우는 없다.
        - closest('css선택자') : 탐색한 노드를 기준으로 css선택자와 일치하는
                                가장 가까운 조상을 탐색,
                                노드가 없을 경우 null 반환<br>
        <div>
            <p id="pText">한국스마트정보교육원</p>
        </div>
        <script>
    
          const $pTextEle = document.querySelector('#pText');
          console.log($pTextEle.parentNode);
          console.log($pTextEle.parentElement);
          console.log($pTextEle.closest('div'));
    
        </script>
    
        <h2>형제 노드 탐색</h2>
        - previousSibling: 이전 형제노드 반환(요소노드뿐만 아니라 텍스트노드포함) <br>
        - nextSibling: 다음 형제노드 반환 반환(요소노드뿐만 아니라 텍스트노드포함)<br>
        - previousElementSibling: 이전 형제 요소 노드 반환<br>
        - nextElementSibling: 다음 형제 요소 노드 반환<br>
        - 노드 탐색 후 없을 시 null 반환<br>
        
        <ul id="ksmartRoom">
            <li class="room301">강의실 301호</li>
            <li class="room302">강의실 302호</li>
            <li class="teacher-room">교직원실</li>
            <li class="counseling-room">상담실</li>
        </ul>
    
        <script>
    
          const $room302Ele = document.querySelector('.room302');
    
          // 이전 형제노드 반환(요소, 텍스트 노드)
          console.log($room302Ele.previousSibling);
    
          // 다음 형제노드 반환(요소, 텍스트 노드)
          console.log($room302Ele.nextSibling);
    
          // 이전 형제노드 반환(요소만)
          console.log($room302Ele.previousElementSibling);
    
          // 다음 형제노드 반환(요소만)
          console.log($room302Ele.nextElementSibling);
    
          const $ksmartRoom = document.querySelector('#ksmartRoom');
          console.log($ksmartRoom.children[3].nextElementSibling, '형제노드 없을시 null 반환');
    
        </script>
    
    </body>
    </html>

04. DOM 조작

  • 요소노드 조작
    💡
    새로운 노드를 생성하여 DOM에 추가하거나 기존 노드를 삭제 또는 교체 하는것

    ➡️ innerHTML

    👉🏻
    setter와 getter 모두 존재하는 접근자 프로퍼티(속성)

    HTML 마크업 수정 및 반환 가능

    ➡️ textContent

    👉🏻
    setter와 getter 모두 존재하는 접근자 프로퍼티(속성)

    요소노드의 모든 텍스트(자식노드 포함)를 반환

    단, HTML 마크업은 무시

    ➡️ nodeValue

    👉🏻
    setter와 getter 모두 존재하는 접근자 프로퍼티(속성)

    텍스트노드의 프로퍼티(vs textContent는 요소노드의 모든 텍스트)

    즉, 텍스트노드 이외의 노드에서는 null를 반환

  • [코드예제] 요소노드 조작
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <link rel="icon" href="data:,">
        <title>DOM 조작</title>
    </head>
    <body>
        <h1>DOM 조작</h1>
        - 새로운 노드를 생성하여 DOM에 추가하거나 기존 노드를 삭제 또는 교체하는 것
        
        <h2>innerHTML</h2>
        - setter와 getter 모두 존재하는 접근자 프로퍼티(속성)<br>
        - HTML 마크업 수정 및 반환 가능<br><br>
        
        <div id="blog">
            멋쟁이v님의<span>개발일지</span>
        </div>
    
        <div id="exDiv"></div>
    
        <script>
    
          const $blogEle = document.getElementById('blog');
          console.log($blogEle.innerHTML) // 공백 포함
          $blogEle.innerHTML = '<h3>블로그</h3>'
          /**
           * ul 태그를 삽입하여
           * 팀명 : 000
           * 팀장 : 000
           * 팀원 : 000
           * exDiv 영역 안에 추가
           */
    
          const $exDivEle = document.getElementById('exDiv');
    
          let html = '<ul>';
              html += '  <li>팀명 : 2팀</li>';
              html += '  <li>팀장 : 홍길동</li>';
              html += '  <li>팀원 : 이길동</li>';
              html += '  <li>팀원 : 삼길동</li>';
              html += '</ul>';
    
          $exDivEle.innerHTML = html;
    
        </script>
    
        <h2>textContent</h2>
        - setter와 getter 모두 존재하는 접근 프로퍼티(속성)<br>
        - 요소노드의 모든 텍스트(자속노드 포함)를 반환<br>
        - 단, HTML 마크업은 무시
    
        <div id="ks47">
          <div id="team">
            <ul>
              <li>1팀</li>
              <li>2팀</li>
              <li>3팀</li>
            </ul>
          </div>
        </div>
    
        <script>
    
          const $ks47Ele = document.getElementById('ks47');
          console.log($ks47Ele.textContent);
          $ks47Ele.textContent = html;
    
        </script>
    
        <h2>nodeValue</h2>
        - setter와 getter 모두 존재하는 접근자 프로퍼티(속성)<br>
        - 텍스트노드의 프로퍼티(vs textContent는 요소노드의 모든 텍스트)<br>
        - 즉, 텍스트노드 이외의 노드에서는 null를 반환
        <div><span id="sText">경력자같은 신입 개발자</span></div>
    
        <script>
    
          const $sTextEle = document.getElementById('sText');
          console.log($sTextEle.firstChild.nodeValue);
          $sTextEle.firstChild.nodeValue += ' 47기';
          console.log($sTextEle.nodeValue, '요소노드에서 nodeValue프로퍼티 접근시 반환값');
    
        </script>
    
    </body>
    </html>

05. 요소노드 생성 / 이동 / 삭제

  • 노드 생성과 추가
    💡
    DOM은 노드를 직접 생성/삽입/삭제/치환하는 메소드를 제공

    반드시 문서노드를 통해 호출

    ➡️ createElement : 요소노드 생성

    ➡️ createTextNode : 텍스트 노드 생성

    ➡️ append(노드, 문자열) : 자식노드 끝에 삽입

    ➡️ prepend(노드, 문자열) : 자식노드 앞에 삽입

    ➡️ before(노드, 문자열) : 해당 노드 이전에 삽입

    ➡️ after(노드, 문자열) : 해당 노드 이후에 삽입

    ➡️ insertBefore(새로운노드, 위치) : 노드 이동 및 특정 위치에 삽입

    ➡️ replaceChild(새로운노드, 위치) : 노드 교체

    ➡️ removeChild(위치) : 노드 삭제

    ➡️ cloneNode(deep 복사여부 [true || false]) : false일 경우 자식노드까지는 복사되지 않는다. true일 경우 자손노드 전체 복사

  • [코드예제] 노드 생성과 추가
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <link rel="icon" href="data:,">
        <title>DOM</title>
    </head>
    <body>
    
        <div>
            <label>배려와 존중이 넘치는 블로그</label>
            <ul id="ksmartTeamUl">
                <li>가이드: 선생님</li>
            </ul>
        </div>
    
        <script>
    
          const $ksmartTeamUlEle = document.getElementById('ksmartTeamUl');
    
          // 요소 노드 생성
          const $newLiEle = document.createElement('li');
    
          // 텍스트 노드 생성
          const $newTxtEle = document.createTextNode('팀명 : 1팀');
    
          // li 요소노드를 완성 => <li>팀명 : 1팀</li>
          $newLiEle.append($newTxtEle);
    
          // append : 취득한 요소의 마지막 자식 요소 뒤에 생성된 요소 추가
          $ksmartTeamUlEle.append($newLiEle);
    
          // 요소 노드 생성
          const $newLiEle2 = document.createElement('li');
          // 요소 노드의 텍스트 노드 값을 셋팅
          $newLiEle2.textContent = '기수 : ksmart47';
    
          // prepend : 취득한 요소의 첫번째 자식 요소 이전에 생성된 요소 추가
          $ksmartTeamUlEle.prepend($newLiEle2);
    
          // before : 취득한 요소를 기점으로 이전에 텍스트 노드 및 요소노드 추가
          $ksmartTeamUlEle.before('멋쟁이v 개발일지 before');
          // after : 취득한 요소를 기점으로 이후에 텍스트 노드 및 요소노드 추가
          $ksmartTeamUlEle.after('멋쟁이v 개발일지 after');
    
        </script>
    
        <div>
            <label>배려와 존중이 넘치는 블로그</label>
            <ul id="ksTeam">
                <!-- 팀명: xxx -->
                <li>가이드: 선생님</li>
                <!-- 각팀의 팀원을 추가하시오. -->
            </ul>
        </div>
    
        <script>
          const teamMemberArr = [
                                    '팀장 : 홍길동',
                                    '팀원 : 일길동',
                                    '팀원 : 이길동',
                                    '팀원 : 삼길동',
                                    '팀원 : 사길동',
                                    '팀원 : 오길동',
                                    '팀원 : 육길동',
                                ]
    
          const $ksTeamEle = document.getElementById('ksTeam');
          const $domFragment = document.createDocumentFragment();
    
          /*
          for(let ele of teamMemberArr) {
            const $teamArrEle = document.createElement('li');
            $teamArrEle.textContent = ele;
            $domFragment.append($teamArrEle);
            $ksTeamEle.append($domFragment);
          }
          */
    
          teamMemberArr.forEach(item => {
            const $newEle = document.createElement('li');
            $newEle.textContent = item;
            $domFragment.append($newEle);
          });
          const $newEle = document.createElement('li');
          $newEle.textContent = '팀명 : 플라플라';
          $ksTeamEle.append($domFragment);
          $ksTeamEle.prepend($newEle);
    
          /*
          const $domFragment = document.createDocumentFragment();
          const $newTeam1 = document.createElement('li');
          $newTeam1.textContent = '팀원1 : 뉴비1';
          $domFragment.append($newTeam1);
          const $newTeam2 = document.createElement('li');
          $newTeam2.textContent = '팀원2 : 뉴비2';
          $domFragment.append($newTeam2);
    
          $ksTeamEle.append($domFragment);
          */
    
        </script>
    
        <h2>노드 이동 및 특정 위치에 삽입</h2>
        <h3>insertBefore(새로운노드, 위치)</h3>
        <script>
    
          const $newLiTag = document.createElement('li');
          $newLiTag.textContent = '팀원3: 뉴비3';
          $ksTeamEle.insertBefore($newLiTag, $ksTeamEle.children[4]);
          const targetEle = [...$ksTeamEle.children].splice(4, 1);
          console.log(targetEle[0]);
          $ksTeamEle.insertBefore($newLiTag, $ksTeamEle.children[$ksTeamEle.children.length-1]);
    
        </script>
    
        <h2>노드 교체 및 노드 삭제</h2>
        <h3>replaceChild(새로운 노드, 노드 위치) - 교체</h3>
        <h3>removeChild(노드 위치) - 삭제</h3>
        <script>
    
    			const newLiEle3 = document.createElement('li');
    	    newLiEle3.textContent = '팀원4: 뉴비4';
    	    $ksTeamEle.replaceChild(newLiEle3, $ksTeamEle.children[8]);
    	    $ksTeamEle.removeChild($ksTeamEle.children[8]);
    
        </script>
    
        <h2>노드복사</h2>
        - cloneNode(deep 복사여부 [true || false])<br>
        - false일 경우 자식노드까지는 복사되지 않음<br>
        - true일 경우 자손노드 전체 복사<br>
        
        <ul class="ex-clone">
            <li class="li-tag">텍스트노드</li>
        </ul>
    
        <script>
    
    			const $exClone = document.querySelector('.ex-clone');
    	    const $exCloneChild = $exClone.querySelector('.li-tag');
    	    // cloneNode() == cloneNode(false) : 해당 타겟 노드만 복사 (자식노드x)
    	    const copyEle1 = $exCloneChild.cloneNode();
    	    // cloneNode(true) : 해당 타겟 노드와 자손노드 복사
    	    const copyEle2 = $exCloneChild.cloneNode(true);
    	
    	    $exClone.append(copyEle1);
    	    $exClone.append(copyEle2);
    
        </script>
    
    </body>
    </html>

06. DOM 실습

  • [코드예제] 실습
    <!DOCTYPE html>
    <html>
    <head>
      <meta charset="UTF-8">
      <link rel="icon" href="data:,">
      <title>DOM 조작</title>
      <style>
        table{
          border: 1px solid black;
          width: 700px;
          table-layout: fixed;
          text-align: center;
        }
        th, td{
          border: 1px solid black;
        }
      </style>
    </head>
    <body>
      <h1>DOM조작 실습</h1>
      <div id="memberList">
        
      </div>
    	실습1. 패턴에 맞춰 객체를 다음 div 영역에 테이블을 삽입하시오.
    	<script type="text/javascript">
        // 패턴 '회원아이디': id001, '회원이름': 홍01, '회원연락처': 010-1111-1111
        // 패턴 '회원아이디': id002, '회원이름': 홍02, '회원연락처': 010-2222-2222
        const memberList = [];
        for(let i = 0; i<10; i+=1) {
            const memberInfo = {};
            memberInfo['회원아이디'] = `id${String(i).padStart(3, 0)}`;
            memberInfo['회원이름'] = `홍${String(i).padStart(2, 0)}`;
            memberInfo['회원연락처'] = `010-${String(i).padStart(4, i)}-${String(i).padStart(4, i)}`;
            memberList.push(memberInfo);
        }
        console.log(memberList);
    
        createTable(memberList, '#memberList')
    
        function createTable(data, selector) {
            const $targetDiv = document.querySelector(selector);
    
            const $table = document.createElement('table');
            const $thead = document.createElement('thead');
            const $tbody = document.createElement('tbody');
            const $theadTr = document.createElement('tr');
    
            data.forEach((item, idx) => {
                const $tbodyTr = document.createElement('tr');
    
                for (key in item) {
                    if (idx == 0) {
                        const $th = document.createElement('th');
                        $th.textContent = key;
                        $theadTr.append($th);
                    }
                    const $td = document.createElement('td');
                    $td.textContent = item[key];
                    $tbodyTr.append($td);
                }
                $tbody.append($tbodyTr);
            });
            $thead.append($theadTr);
            $table.append($thead);
            $table.append($tbody);
            $targetDiv.append($table);
        }
    
    
    		
    	</script>
      <h1>DOM조작 실습</h1>
      <input type="number" min="2" max="9" value="2"/>
      <button id="guguBtn">구구단 출력</button>
      <br><br>
      <div id="resultGugu"></div>
      <br><br><br><br>
      <!-- <table>
        <thead>
          <tr>
            <th>2단</th>
            <th>3단</th>
            <th>4단</th>
            <th>5단</th>
            <th>6단</th>
            <th>7단</th>
            <th>8단</th>
            <th>9단</th>
          </tr>
        </thead>
        <tbody id="guguTbody">
    
        </tbody>
      </table> -->
      실습2. tbody 영역에 구구단 테이블을 삽입하시오.
      <script type="text/javascript">
    
        const $guguBtnEle = document.getElementById('guguBtn');
        $guguBtnEle.onclick = () => {
            const $resultGugu = document.getElementById('resultGugu');
            $resultGugu.innerHTML = ' ';
            const $input = document.querySelector('input[type="number"]')
            let times = $input.value;
            const guguArr = [];
            for(let i = 1; i<10; i+=1) {
                const result = {};
                for(let j = 2; j<=times; j+=1) {
                    result[`${j}단`] = `${j} x ${i} = ${j*i}`;
                }
                guguArr.push(result);
            }
            createTable(guguArr, '#resultGugu');
        }
    
      </script>
    </body>
    </html>

07. 어트리뷰트 노드

💡
HTML 요소는 여러 개의 어트리뷰트(속성)을 가질 수 있다.

➡️ 어트리뷰트 이름 = ‘어트리뷰트 값’ 형식으로 정의

➡️ 모든 요소노드는 Element.prototype.attribute로 취득 가능

➡️ attribute 프로퍼티는 getter만 존재하는 읽기 전용 접근자 프로퍼티

➡️ NamedNodeMap 객체 반환

  • 종류
    👉🏻
    글로벌 어트리뷰트 : id, class, style, title, data-* 등

    이벤트 핸들러 어트리뷰트 : onclick, onchange, onfocus, onblur, oninput 등

  • HTML 어트리뷰트 조작
    👉🏻
    attributes 프로퍼티는 getter만 존재하므로 변경할 수 없다.

    요소노드에서 메소드를 통해 조작 가능

    ➡️ Element.prototype.getAttribute / Element.prototype.setAttribute

    • getAttribute(’속성’) = 값 반환
    • setAttribute(’속성’, ‘값’)

  • 어트리뷰트 propertie vs DOM propertie
    👉🏻
    어트리뷰트 프로퍼티(초기상태 값 유지)

    DOM 프로퍼티(동적, 최신상태)

  • data 어트리뷰트와 dataset 프로퍼티
    👉🏻
    HTML 요소에 정의한 사용자 정의 어트리뷰트와 자바스크립트 간에 데이터를 교환

    ➡️ data 어트리뷰트의 값은 dataset 프로퍼티로 취득가능

    ➡️ 해당 요소에 특정한 데이터를 잠시 저장하는 용도

  • 스타일
    👉🏻
    인라인 스타일 조작

    ➡️ HTMLElement.prototype.style : setter와 getter 모두 존재하는 접근자 프로퍼티

  • 클래스 조작
    💡
    className

    ➡️ HTMLElement.prototype.className : setter와 getter 모두 존재하는 접근자 프로퍼티

    ➡️ 클래스 변경 : replace(’변경할 클래스명’, ‘새로운 클래스명’)

    💡
    classList

    ➡️ HTMLElement.prototype.classList : setter와 getter 모두 존재하는 접근자 프로퍼티

    • 클래스 추가 : add(’클래스명’)
    • 클래스 삭제 : remove(’클래스명’)
    • 특정 클래스 가져오기 : item(’index 번호’)
    • 특정 클래스 포함여부 : contains(’클래스명’)
    • 클래스 변경 : replace(’변경할 클래스명’, ‘새로운 클래스명’)
    • 클래스 제거 및 추가 : toggle(’대상 클래스명’) - 대상 클래스명과 일치하는 클래스명 삭제하고 일치하는 클래스명이 없으면 추가한다.

  • [코드예제] 어트리뷰트 노드
    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <link rel="icon" href="data:,">
        <title>어트리뷰트 노드 조작</title>
    </head>
    <body>
        <h1>어트리뷰트 노드</h1>
        - HTML 요소는 여러 개의 어트리뷰트 (속성)을 가질 수 있다.<br>
        - 어트리뷰트이름 = '어트리뷰트값' 형식으로 정의<br>
        - 모든 요소노드는 Element.prototype.attribute로 취득 가능<br>
        - attribute 프로퍼티는 getter만 존재하는 읽기 전용 접근자 프로퍼티<br>
        - NamedNodeMap 객체 반환<br>
    
        <h1>어트리뷰트 종류</h1>
        - 글로벌 어트리뷰트 : id, class, style, title, data-* 등<br>
        - 이벤트 핸들러 어트리뷰트: onclick, onchange, onfocus, onblur, oninput 등<br><br>
    
        <input type="text" id="ksmart" value="신입개발자">
        <button type="button" onclick="alert('경고btn')">경고btn</button>
    
        <form>
          <input type="text" name="id" value="입력하세요.">
          <!-- reset : 폼 안에 있는 입력을 받을 수 있는 요소들의 초깃값으로 되돌린다. -->
          <input type="reset" value="취소">
        </form>
    
        <script>
    
          // 속성에 있는 값을 가져오는 여러 방법들
          const $ksmartEle = document.getElementById('ksmart');
          console.log({$ksmartEle});
          console.log($ksmartEle.attributes.item(1).value);
          console.log($ksmartEle.attributes.id.value);
          console.log($ksmartEle.id);
    
          console.log($ksmartEle.attributes.item(0).value);
          console.log($ksmartEle.attributes.type.value);
          console.log($ksmartEle.type);
    
        </script>
    
        <h2>HTML 어트리뷰트 조작</h2>
        - attributes 프로퍼티는 getter만 존재하므로 변경할 수 없다<br>
        - 요소노드에서 메소드를 통해 조작 가능<br>
        - Element.prototype.getAttribute / Element.prototype.setAttribute<br>
        - getAttribute('속성') = 값 반환<br>
        - setAttribute('속성', '값')<br>
    
        <input type="text" id="ksStudent" value="경력자같은 신입개발자"/>
    
        <script>
    
          const $ksStudentEle = document.getElementById('ksStudent');
          console.log($ksStudentEle.getAttribute('value'));
          $ksStudentEle.setAttribute('value', '신입개발자');
          console.log($ksStudentEle.getAttribute('value'));
    
        </script>
    
        <h2>어트리뷰트 propertie vs DOM propertie</h2>
        - 어트리뷰트 propertie(초기상태 값 유지)<br>
        - DOM propertie(동적, 최신상태)<br>
    
        <input type="text" id="ks47Student" value="개발자 47기">
        <button type="button" id="exBtn">프로퍼티 확인</button>
    
        <script>
    
          const $exBtn = document.getElementById('exBtn');
    
          $exBtn.onclick = function () {
            const $ks47Student = document.getElementById('ks47Student');
            console.log($ks47Student.attributes.value.value);
            console.log($ks47Student.getAttribute('value'));
            console.log($ks47Student.value); // DOM 프로퍼티 : 요소노드에서 직접적으로 속성노드
          }
    
        </script>
    
        <h2>data 어트리뷰트와 dataset 프로퍼티</h2>
        - HTML 요소에 정의한 사용자 정의 어트리뷰트와 자바스크립트 간에 데이터를
            교환<br>
        - data 어트리뷰트의 값은 dataset 프로퍼티로 취득가능<br>
        - 해당 요소에 특정한 데이터를 잠시 저장하는 용도<br>
    
        <button id="addGoodsBtn"
                type="button"
                data-seller-id="id001"
                data-goods-code="g001"
                data-goods-name="모니터"
                data-goods-price="1000000">상품등록</button>
    
        <div class="ex-data">
        </div>
        <br>
        <!-- 실습. data속성을 값을 활용하여 아래 #teamUl요소 안 list완성하시오-->
        <!-- ex:) teamName : 우리는 하나다 -->
        <button id="teamBtn"
                type="button"
                data-team-name="우리는 하나다"
                data-team1="김영희"
                data-team2="이철수"
                data-team3="홍길동"
                >팀구성</button>
        <ul id="teamUl">
    
        </ul>
        <form id="modifyGoodsForm">
          <label for="goodsName">상품명</label>
          <input type="text" id="goodsName" name="goodsName" value="모니터"/> <br>
          <label for="goodsPrice">상품가격</label>
          <input type="text" id="goodsPrice" name="goodsPrice" value="1000000"/> <br>
          <label for="goodsAmount">상품수량</label>
          <input type="text" id="goodsAmount" name="goodsAmount" value="200"/> <br>
          <button type="button" id="modifyBtn" data-goods-code="g001">수정</button>
        </form>
    
        <script>
    			// 예제1
          // data 어트리뷰트는 dataset 프로퍼티로 접근
          const $addGoodsBtn = document.getElementById('addGoodsBtn');
          console.log($addGoodsBtn.dataset);
          console.log($addGoodsBtn.dataset.sellerId); // id001
          console.log($addGoodsBtn.getAttribute('data-seller-id')); // id001
    
          // 데이터를 가져올때 미리 정의 해놓을 수 있다.
          const goodsData = $addGoodsBtn.dataset;
          console.log(goodsData.sellerId);
          
    			// 예제2
          const $teamUl = document.getElementById('teamUl');
          const $teamBtn = document.getElementById('teamBtn');
    
          $teamBtn.onclick = function () { // 버튼 클릭시 함수 실행
            const dataObj = this.dataset;
    				// dataset은 객체 형태 > 순회 방법 : for in
            for(let key in dataObj) {
              const $li = document.createElement('li');
              $li.textContent = `${key} : ${dataObj[key]}`
              $teamUl.append($li);
            }
          }
    
          // form의 값을 객체로 저장, {key : value}
          const $modifyBtn = document.getElementById('modifyBtn');
          $modifyBtn.onclick = function () { // 버튼 클릭시 함수 실행
            console.log(this.dataset.goodsCode); // data-goods-code의 값 : g001
            const $inputEles = document.querySelectorAll('#modifyGoodsForm input'); // id값이 modifyGoodsForm이고, 그 안에 input 태그인 모든 요소를 취득
            const goodsInfo = {} // 상품을 담을 객체 생성
    	      $inputEles.forEach(item => { // nodeList로 담겨진 유사배열을 순회한다.
    	        let name = item.name; // input태그 name 값을 가져온다.
    	        let value = item.value; // input 태그 value 값을 가져온다.
    	        goodsInfo[name] = value; // 객체에 name(키), value(값) 으로 담는다.
    	      });
    	      for(let key in this.dataset){ // dataset에 있는 데이터 : {goodsCode : 'g001'}
    	        goodsInfo[key] = this.dataset[key]; // 객체에 담는다.
    	      }
    	      console.log(goodsInfo);
    	    }
    
          const $modify = document.getElementById('modifyBtn');
          $modify.onclick = function () {
            const $form = document.querySelectorAll('#modifyGoodsForm input');
            const goodsInfo = {};
            console.log($form);
            $form.forEach(item => {
              let name = item.name;
              let value = item.value;
              goodsInfo[name] = value;
            });
            for(let key in this.dataset) {
              goodsInfo[key] = this.dataset[key];
            }
            console.log(goodsInfo);
          }
    
    
        </script>
    
        <h2>스타일</h2>
    
        <h3>인라인 스타일 조작</h3>
        - HTMLElement.prototype.style: setter와 getter 모두 존재하는 접근자 프로퍼티<br>
        <div class="ksmart-team">
            <div>
                <span>배려와 존중이 넘치는 블로그</span>
                <ul>
                    <li>가이드: 멋쟁이v</li>
                </ul>
            </div>
        </div>
        <script>
    
          const $ksmartDiv = document.querySelector('.ksmart-team');
          const $divEle = document.querySelector('.ksmart-team > div');
          const $spanEle = $divEle.querySelector('span');
          const $ulEle = $divEle.querySelector('ul');
          let ksmartDivStyle = $ksmartDiv.style;
          //console.log(ksmartDivStyle);
    
          $ksmartDiv.style.color = 'yellow';
          $ksmartDiv.style.position = 'relative';
          $ksmartDiv.style.width = '400px';
          $ksmartDiv.style.height = '100px';
          $ksmartDiv.style.display = 'flex';
          $ksmartDiv.style.justifyContent = 'center';
          $ksmartDiv.style.alignItems = 'center';
          $ksmartDiv.style.backgroundColor = 'blue';
    
          $divEle.style.border = '1px solid yellow';
          $divEle.style.width = '330px';
          $divEle.style.padding = '5px';
    
          $spanEle.style['display'] = 'block';
          $spanEle.style['text-align'] = 'center';
    
        </script>
    
        <h2>클래스 조작</h2>
        <h3>className</h3>
        - HTMLElement.prototype.className: setter와 getter 모두 존재하는 접근자 프로퍼티<br>
        - 클래스 변경 : replace('변경할 클래스명', '새로운 클래스명')<br>
    
        <p class="p-Ksmart">멋쟁이v의 개발일지</p>
    
        <script>
    
          const $pKsmart = document.querySelector('.p-Ksmart');
          console.log($pKsmart.className); // 겟팅
          $pKsmart.className = 'ks47'; // 셋팅 (덮어써버린다)
          console.log($pKsmart.className);
    
        </script>
    
        <h3>classList</h3>
        - HTMLElement.prototype.classList: setter와 getter 모두 존재하는 접근자 프로퍼티<br>
        - 클래스 추가 : add('클래스명')<br>
        - 클래스 삭제 : remove('클래스명')<br>
        - 특정 클래스 가져오기 : item('index 번호')<br>
        - 특정 클래스 포함여부 : contains('클래스명')<br>
        - 클래스 변경 : replace('변경할 클래스명', '새로운 클래스명')<br>
        - 클래스 제거 및 추가 : toggle('대상 클래스명') #대상 클래스명과 일치하는 클래스명 삭제하고 일치하는 클래스명이 없으면 추가<br>
                               ex: toggle('클래스명') <br>
                                   인수 1개 일 경우 클래스명이 없을 경우 추가, 클래스명이 있을 경우 삭제 <br>
                                   toggle('클래스명', boolean) <br>
                                   인수 2개 일 경우 true:클래스명 추가, false: 클래스명 삭제 <br>
    
        <p class="ksmart-dev">글로벌 최상위 1% ICT 전문가</p>
    
        <script>
    
          const $ksmartDev = document.querySelector('.ksmart-dev');
          console.log($ksmartDev.classList);
          const ksDevClassList = $ksmartDev.classList;
          ksDevClassList.add('ks-47'); // class = "ksmart-dev ks-47"
          ksDevClassList.remove('ksmart-dev') // class = "ks-47"
          console.log(ksDevClassList.item(0)); // ks-47
          console.log(ksDevClassList.contains('ks-47')); // true
          ksDevClassList.replace('ks-47', 'ksmart-47');
    
          // toggle('클래스명') 해당 클래스명이 존재하면 삭제, 존재하지 않으면 추가
          ksDevClassList.toggle('ks47'); // 추가
          ksDevClassList.toggle('ks-developer'); // 추가
          ksDevClassList.toggle('ksmart-47'); // 삭제
    
          // toggle('클래스명', boolean) 2번째 인수가 true : 추가, false : 삭제
          ksDevClassList.toggle('ksmart-47', true);
          ksDevClassList.toggle('ksmart-47', true); // 중복으로 추가 되는게 아니라 그대로 유지
          ksDevClassList.toggle('ksmart-47', !ksDevClassList.contains('ksmart-47'));
    
          console.log($ksmartDev.classList);
    
        </script>
    
    </body>
    </html>


tag : #javascript #DOM #노드 #요소 #텍스트 #취득 #탐색 #조작 #생성 #이동 #삭제 #어트리뷰트 #dataset #스타일조작 #클래스조작


Uploaded by N2T

728x90
320x100

'0년차 > Javascript' 카테고리의 다른 글

[Javascript] jQuery  (0) 2023.08.19
[Javascript] DOM객체 이벤트  (0) 2023.05.20
[Javascript] 브라우저렌더링, 브라우저 객체(BOM)  (1) 2023.05.14
[Javascript] 예외처리  (0) 2023.04.29
[Javascript] 내장객체  (0) 2023.04.29
Comments