[Web] JavaScript DOM 조작하기, 여러 메서드 + 예제
HTML을 동적으로 다양하게 변화를 주기 위해 DOM API를 활용해야한다. 라이브러리를 쓰는 것 보다 속도 차이가 크지는 않지만 대체로 더 빠른 편이다.
참고
document. 의 api들 > https://www.w3schools.com/jsref/dom_obj_document.asp
element. 의 api들 > https://www.w3schools.com/jsref/dom_obj_all.asp
firstChild : 첫번째 자식 노드를 찾아준다. 하지만 공백이나 텍스트 노드를 가져 올 수 있다.
firstElementChild : 첫번째 element 자식 노드를 찾아준다.
DOM 조작 API
유용한 DOM 엘리먼트 속성
예제 실습
'fruit.html'
문제1 ) insertBefore() 를 사용해 orange와 banana 사이에 과일을 추가하라
insertBefore의 문법 :
"부모노드.insertBefore(삽입할 자식 노드, 기준 자식 노드)"
문제2) 위의 문제를 InsertAdjacentHTML() 을 사용하여 풀어라
insertAdjacentHTML의 문법:
"부모노드.insertAdjacentHTML('position',"html") "
position에는 아래의 4가지가 있다.
문제3) apple 엘리먼트를 grape와 strawberry 사이에 위치하도록 옮겨라
! insertBefore 는 clone 하는 것이 아니라 이미 존재하는 노드를 다른 위치로 이동시켜준다.
문제4) class가 red인 노드만 삭제하라
(위 html에 apple, orange 가 red 클래스에 추가된 상태)
처음에는 querySeletor로 element를 받아왔는데 첫번째 red 인 apple 만 삭제가 되었다. 다음으로 getElementsByClassName 메소드를 사용했는데 이번에도 apple 만 삭제가 되었다. 개발자 도구를 켜 확인해보니 undefined element에 대해 remove를 수행할 수 없다는 오류가 나왔다.
찾아보니 getElementsByClassName 는 live list를 반환하기 때문에 내가 remove를 수행하면 첫번째 엘리먼트가 지워지고 나서 두번째 엘리먼트가 첫번째 엘리먼트가 되기 때문에 반복문을 돌면서 두번째 index로 지우려고 해도 그 자리엔 아무것도 없기때문에 오류가 발생한다. 따라서 querySeletorAll()을 사용해야 한다.
! remove()는 IE 에서 호환되지 않는다. 호환성이 좋은 removeChild를 쓰는 것도 꼭 알아둘 것
문제 5) section 태그의 자손중 blue 라는 클래스를 가진 노드가 있다면 그 하위에 있는 h2 노드를 삭제해라
1. 가장 비효율적으로 내가 쓴 답
2. closest 메서드 활용
3. for문을 forEach로
4. Array.from() 메서드 사용
참고
위키피디아 DOM 설명 : https://en.wikipedia.org/wiki/Document_Object_Model
참고
document. 의 api들 > https://www.w3schools.com/jsref/dom_obj_document.asp
element. 의 api들 > https://www.w3schools.com/jsref/dom_obj_all.asp
firstChild : 첫번째 자식 노드를 찾아준다. 하지만 공백이나 텍스트 노드를 가져 올 수 있다.
firstElementChild : 첫번째 element 자식 노드를 찾아준다.
DOM 조작 API
- removeChild()
- appendChild()
- insertBefore()
- clondNode()
- replaceChild()
- closest() //상위로 올라가면서 근접 엘리먼트 찾기
var div = document.createElement("div"); var str = documnent.createTextNode("오늘도 화이팅"); div.appendChild(str);
크롬 개발자 도구를 활용해 실제 사이트에서 api들을 연습해 볼 수 있다.
react angular view 템플릿상으로 html을 만들어두고 변경이필요한 data 부분은 바꿔주면 자동으로 렌더링되는 자동화된 방법을 사용하기도 하지만 dom api를 조작하는 것이 표준적 방법이므로 익숙해지는 것이 필요하다.
react angular view 템플릿상으로 html을 만들어두고 변경이필요한 data 부분은 바꿔주면 자동으로 렌더링되는 자동화된 방법을 사용하기도 하지만 dom api를 조작하는 것이 표준적 방법이므로 익숙해지는 것이 필요하다.
var sp1 = document.createElement("span"); var sp2 = document.getElementById("childElement"); var parentDiv = sp2.parentNode; parentDiv.insertBefore(sp1,sp2); //sp2 앞에 sp1을 추가하는 메서드
var parent = document.selectQuery(".w3-example"); parent.innerText("<p>haha</p>"); //query create를 하지 않아도 childNode가 생성된다 parent.innerText = parrnet.innerText+"<p>haha</p>"
유용한 DOM 엘리먼트 속성
- tagName : 엘리먼트의 태그명 반환
- textContent : 노드의 텍스트 내용을 설정하거나 변환
- nodeType : 노드의 노드 유형을 숫자로 변환
DOM 탐색 속성
- childNodes : 엘리먼트의 자식 노드의 노드 리스트 반환 ( textNode, 주석 노드 포함)
- firstChild : 엘리먼트의 첫번째 자식 노드 반환
- firstElementChild : 첫번째 자식 엘리먼트 반환
- parentElement : 엘리먼트의 부모 엘리먼트 반환
- nextSibling : 동일한 노드 트리 레벨에서 다음 노드 반환
- nextElementSibling : 동일한 노드 트리 레벨에서 다음 엘리먼트 반환
DOM 조작 메소드
- removeChild() : 엘리먼트의 자식 노드 제거
- appendChild() : 마지막 자식 노드를 추가
- insertBefore() : 기존 자식노드 앞에 새 자식 노드 추가
- cloneNode() : 엘리먼트의 자식 노드 복제
- replaceChild() : 엘리먼트의 자식 노드 바꾸기
- closest() : 상위로 올라가면서 가장 가까운 엘리먼트를 반환
HTML을 문자열로 처리해주는 DOM 속성 / 메소드
- innerText : 지정된 노드와 모든 자손의 텍스트 내용을 설정하거나 반환
- innerHTML : 지정된 엘리먼트의 내부 HTML을 설정하거나 반환
- innsertAdjacentHTML() : HTML로 텍스트를 지정된 위치에 삽입
예제 실습
'fruit.html'
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <h1>selector test</h1> <ul> <li>apple</li> <li>orange</li> <li>banana</li> <li>grape</li> <li>strawberry</li> </ul> </body> </html>
문제1 ) insertBefore() 를 사용해 orange와 banana 사이에 과일을 추가하라
insertBefore의 문법 :
"부모노드.insertBefore(삽입할 자식 노드, 기준 자식 노드)"
var li = document.querySelector("ul li:nth-child(3)"); var ul = document.querySelector("ul"); var fruit = document.createElement("li"); var text = document.createTextNode("peach"); fruit.appendChild(text); ul.insertBefore(fruit,li);
문제2) 위의 문제를 InsertAdjacentHTML() 을 사용하여 풀어라
"부모노드.insertAdjacentHTML('position',"html") "
position에는 아래의 4가지가 있다.
<!-- beforebegin --> <p> <!-- afterbegin --> foo <!-- beforeend --> </p> <!-- afterend -->
li.insertAdjacentHTML('beforebegin',"<li>peach</li>");
문제3) apple 엘리먼트를 grape와 strawberry 사이에 위치하도록 옮겨라
var li = document.querySelector("li:nth-child(1)"); var berry = document.querySelector("li:nth-child(5)"); var ul = document.querySelector("ul"); ul.insertBefore(li,berry);
문제4) class가 red인 노드만 삭제하라
(위 html에 apple, orange 가 red 클래스에 추가된 상태)
처음에는 querySeletor로 element를 받아왔는데 첫번째 red 인 apple 만 삭제가 되었다. 다음으로 getElementsByClassName 메소드를 사용했는데 이번에도 apple 만 삭제가 되었다. 개발자 도구를 켜 확인해보니 undefined element에 대해 remove를 수행할 수 없다는 오류가 나왔다.
찾아보니 getElementsByClassName 는 live list를 반환하기 때문에 내가 remove를 수행하면 첫번째 엘리먼트가 지워지고 나서 두번째 엘리먼트가 첫번째 엘리먼트가 되기 때문에 반복문을 돌면서 두번째 index로 지우려고 해도 그 자리엔 아무것도 없기때문에 오류가 발생한다. 따라서 querySeletorAll()을 사용해야 한다.
var red = document.querySelectorAll('.red'); for (var i=0;i<red.length;i++){ red[i].remove(); }
var red = document.querySelectorAll('.red'); red.forEach(function(el){ el.remove(); })
var reds = document.querySelectorAll(".red"); var ul = document.querySelector("ul"); for(var i=0;i<reds.length;i++){ ul.removeChild(reds[i]); }
! remove()는 IE 에서 호환되지 않는다. 호환성이 좋은 removeChild를 쓰는 것도 꼭 알아둘 것
문제 5) section 태그의 자손중 blue 라는 클래스를 가진 노드가 있다면 그 하위에 있는 h2 노드를 삭제해라
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width"> <title>JS Bin</title> </head> <body> <h1>selector test</h1> <section> <h2> red section </h2> <ul> <li class="red">apple</li> <li class="red">orange</li> <li>banana</li> <li>grape</li> <li>strawberry</li> </ul> </section> <Br> <section> <h2> blue section </h2> <ul> <li class="green blue">apple</li> <li class="red">orange</li> <li>banana</li> <li>grape</li> <li>strawberry</li> </ul> </section> </body> </html>
1. 가장 비효율적으로 내가 쓴 답
var blue = document.getElementsByClassName("blue"); for(var i=0;i<blue.length;i++){ var parent = blue[i].parentElement; var section = parent.parentElement; var h2 = section.getElementsByTagName("h2"); for(var j=0;j<h2.length;j++) h2[j].remove(); }
2. closest 메서드 활용
var bluenode = document.querySelectorAll("section .blue"); for(var i =0;i<bluenode.length;i++){ var section = bluenode[i].closest("section"); var h2 = section.querySelector("h2"); section.removeChild(h2); }
3. for문을 forEach로
var bluenode = document.querySelectorAll("section .blue"); bluenode.forEach(function(element){ var section = element.closest("section"); var h2 = section.querySelector("h2"); section.removeChild(h2); })
4. Array.from() 메서드 사용
var bluenode = document.querySelectorAll("section .blue"); Array.from(bluenode).forEach(function(v){ var section = v.closest("section"); var h2 = section.querySelector("h2"); section.removeChild(h2); });
참고
위키피디아 DOM 설명 : https://en.wikipedia.org/wiki/Document_Object_Model
No comments: