DOM - create, read, update, delete

Document 객체

  • 웹 페이지 자체로서, 페이지 콘텐츠(tree구조)의 진입점
  • 웹 페이지의 html 요소에 접근 하기 위해서는 document 객체를 통해야 한다.


Node vs. Element

  • node: DOM의 가장 기본이 되는 데이터 타입
  • node 타입에 따라 구분된 하위 클래스: Document, Element, DocumentFragment
  • 노드 기능을 구현하는 모든 오브젝트들이 이런 하위 클래스 중 하나를 기반으로 하는 것
  • Node > Element


자식, 부모 element 찾기

  • 자식 엘리먼트 찾기: parentNode.children
  • 부모 엘리먼트 찾기: node.parentElement
<body>
   <div class = "mom">
     <div class="daughter"></div>
  </div>
</body>
const parentDiv = document.querySelector('.mom')
const childDiv = document.querySelector('.daughter')

document.body.children[0] // 결과값: <div class="mom">...</div>
parentDiv.children // 결과값: HTMLCollection [div.daughter]
childDiv.parentElement // 결과값: <div class="mom">...</div>


Create - element 생성: createElement, append

Document.createElement(‘태그’)

  • html 요소를 만들어 반환하는 메소드. 태그를 지정할 수 있다.
  • tag name을 인식할 수 없을 경우 HTMLUnknownElement를 반환한다.
  • 이 때 만들어진 element는 아직 dom에 연결되지 않은 상태이다.
// div 태그 만들기
const newEl = document.createElement('div');


Document.createDocumentFragment()

  • 비어있는 새 DocumentFragment 생성
  • DocumentFragment: 부모가 없는 document 객체로, 노드를 추가할 수 있는 임시 객체
  • tree구조에 포함되지 않기 때문에 fragment를 변경해도 문서에는 영향을 미치지 않는다. // 가상의 노드 객체
  • children을 추가할 때 브라우저 reflow가 일어나지 않는다. // better performance
  • documentFragment 생성 -> element들을 documentFragment에 추가 -> documentFragment를 DOM tree에 추가


append

  • parentNode.append(노드)
  • 부모 노드의 마지막 자식 뒤에, 즉 맨 끝에 노드 객체 또는 DOMString 객체를 삽입
  • 여러 개 노드와 문자를 추가할 수 있다.
  • rest parameter를 사용할 수 있다. // parentNode.append(…nodes);
  • 반환하는 값이 없다.
  • JavaScript 메소드로 확장성이 뛰어나다.
  • IE(인터넷 익스플로러) 호환 안됨
// parentDiv에 ChildDiv 추가
parentDiv.append(childDiv)


appendChild

  • Node.appendChild()
  • append와 같은 기능: 부모 노드의 자식 노드 맨 끝에 노드 삽입
  • 오직 노드 객체만 추가 가능하다. (문자열 노드는 지원하지 않는다)
  • 추가한 Node 객체를 반환한다.
  • 하나의 노드만 추가할 수 있다. // 노드가 이미 존재할 경우 새로운 위치로 이동시킨다.
  • DOM 메소드
  • IE 호환


append vs. appenChild

  • append는 문자열을 바로 추가할 수 있다.
// 결과: <div id="userId">Hello</div>
// append: 문자열을 바로 추가
document.getElementById('userId').append('Hello!');

// appendChild: 텍스트 노드를 따로 만들어 변수에 저장한 후 parameter를 통해 불러온다.
const addText = document.createTextNode('Hello!');

document.getElementById('userId').appendChild(addText);
  • append는 element와 text를 동시에 추가할 수 있다.
const parentDiv = document.createElement('div');
const childP = document.createElement('p');

parentDiv.append("Add text", childP);
document.body.append(parentDiv) 
// 결과: 
// <div>
//    "Add text"
//    <p></p>
// </div>      


prepend

  • parentNode.prepend()
  • 부모 노드의 첫 자식 노드 앞에, 즉 맨 앞에 노드 객체 또는 DOMString 객체를 삽입
  • 여러 개 노드와 문자를 추가할 수 있다.
  • rest parameter를 사용할 수 있다. // parentNode.prepend(…nodesToPrepend);
  • 반환하는 값이 없다.
  • JavaScript 메소드로 확장성이 뛰어나다.
  • IE(인터넷 익스플로러) 호환 안됨


append vs. prepend

  • 객체를 삽입하는 위치만 다를 뿐 다른 특징은 동일하다.
  • append는 자식노드 맨 끝에, prepend는 자식노드 맨 앞에 객체를 삽입한다.


Read - element 조회: querySelector, querySelectorAll

  • document.querySelector(‘셀렉터’): 하나의 엘리먼트 조회
  • document.querySelecorAll(‘셀렉터’): 모든 엘리먼트 조회
  • get으로 시작하는 DOM 조회 메소드는 오래된 방식: 이전 브라우저 호환성에 대응할 때 사용한다. // getElementById, getElementByClassName, getElementByName


Update - element 갱신: textContent, classList.add

textContent

  • Node.textContent: 태그 안에 텍스트 콘텐츠 추가
childDiv.textContent = '텍스트 추가'
// 결과: <div class="daughter">텍스트 추가<div>


textConctent vs. innerText vs. innerHTML

  • Node.textContent: 모든 요소의 원시 텍스트 반환.
  • HTMLElement.innerText: 원시 텍스트가 화면에 렌더링 된 모습(스타일을 인식하며 숨겨진 요소의 텍스트를 반환하지 않음) => 사람이 읽을 수 있는 요소만 처리
  • Element.innerHTML: HTML을 반환. 요소의 텍스트를 가져오거나 사용할 수 있지만 HTML로 분석할 필요가 없기 때문에 textConctent를 쓰는 것이 더 유용하다. XSS(Cross-Site Scripting) 공격에 취약하다.
  • innerText를 수정 시 요소의 모든 자식 노드와 그 텍스트가 영구히 파괴된다. 이후 해당 텍스트 노드를 새로 삽입하는 것이 불가능하다. innerText 값을 읽을 때 reflow 발생.
  • reflow: 웹 페이지(문서)의 일부 또는 전체를 다시 렌더링 -> 속도가 느려지게 되므로 reflow는 최소화되어야 한다.
  • 결론: textContent가 성능과 보안 면에서 모두 유리하다!


class update: classList

  • element.classList.add(‘클래스명’) : 클래스 값 추가
  • element.classList.remove(‘클래스명’) : 클래스 값 제거
const childDiv2 = document.createElement('div')
// <div></div>

childDiv2.classList.add('son')
// <div class="son"></div>


id update: id

  • element.id : id 값 추가
const parentDiv = document.querySelector('.mom')
// <div class="mom"></div>

parentDiv.id = 'parent'
// <div class"mom" id="parent"></div>


속성 update: setAttribute, removeAttribute

  • element.setAttribute(‘속성name’, ‘속성value’) : 속성값 추가
  • element.removeAttribute(‘속성name’) : 속성값 제거
childDiv2.setAttribute('say', 'helloMom')
// <div class"son" say="helloMom"></div>

childDiv2.removeAttribute('say')
// <div class="son"></div>


Delete - element 삭제: remove, removeChild

  • node.remove() : 해당 엘리먼트 제거
<div id="div-01"></div>
<div id="div-02"></div>
<div id="div-03"></div>
const el = document.querySelector('#div-02')
el.remove()

// 결과
// <div id="div-01"></div>
// <div id="div-03"></div>
  • node.removeChild(child) : 자식 엘리먼트를 지정하여 제거
<div class = "mom">
  <div class="daughter"></div>
  <div class="son"></div>
</div>
const parentDiv = document.querySelector('.mom')
const childDiv = document.querySelector('.daughter')

parentDiv.removeChild(childDiv)

// 부모 노드에 대한 정보가 없을 경우
const childDiv2 = document.querySelector('.son')

if (childDiv2.parentNode) {
  childDiv2.parentNode.removeChild(childDiv2)
}
  • innerHTML : 가장 간편한 방법이지만 보안상 문제(XSS공격)가 있기 때문에 사용하지 않는 것이 좋다.
parentDiv.innerHTML = ''

Categories:

JavaScript

Load Comments