[목차]
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. 어트리뷰트 노드
➡️ 어트리뷰트 이름 = ‘어트리뷰트 값’ 형식으로 정의
➡️ 모든 요소노드는 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