DOM 노드 프로퍼티와 조작

345·2023년 7월 17일

📌 DOM 노드 클래스

DOM 노드에는 요소 노드, 텍스트 노드, 주석 노드 등 다양한 종류가 있습니다.
요소 노드도 <a><input> 등 다양합니다.

이렇듯 노드는 종류에 따라 다른 상속 관계를 가지고, 다른 프로퍼티를 지원하며
계층 구조 꼭대기에 있는 공통 조상에 의해 공통된 프로퍼티를 지원합니다.

계층 관계는 위와 같습니다.

  • EventTarget: 추상 클래스로, DOM 노드에서 이벤트를 사용할 수 있도록 함
  • Node: 추상 클래스로, DOM 노드의 베이스
  • Element: DOM 요소를 위한 베이스 클래스. querySelector 등 지원
  • HTMLElement: HTML 요소 노드의 베이스 클래스

이렇듯, 특정한 노드에서 사용 가능한 메서드, 프로퍼티는 상속을 기반으로 결정됩니다.
DOM 노드는 프로토타입을 기반으로 상속 관계를 갖는 자바스크립트 객체입니다.


innerHTML 으로 HTML 조작하기

innerHTML 프로퍼티는 요소 노드에서 사용 가능한 프로퍼티로,
이를 통해 요소 안의 HTML 을 읽어오고, HTML을 변경할 수도 있습니다.

<body>
  <p>p 태그</p>
  <div>div 태그</div>

  <script>
    alert( document.body.innerHTML ); // 내용 읽기
    document.body.innerHTML = '새로운 BODY!'; // 교체
  </script>

</body>

+= 를 사용하면 기존 HTML 내용에 덧붙일 수도 있습니다.

elem.innerHTML+="추가 html"

그러나, 이건 기존 내용의 삭제를 동반합니다.
원래 내용을 삭제하고 내용 추가 후 전부 다시 로딩하기 때문에 시간이 좀 걸립니다.


✅ 속성과 프로퍼티

HTML 태그 요소의 속성은 대부분 DOM 객체의 프로퍼티가 됩니다.
DOM 노드는 자바스크립트 객체이므로 새로운 프로퍼티를 만들어주거나, prototype 을 수정하여 메서드를 추가해줄 수도 있죠.

속성과 프로퍼티는 완전히 동일한 값을 가지진 않습니다.
a 태그의 href 속성의 경우 a.href 프로퍼티는 현재 사이트 주소 전체에 href 속성을 붙인 값을 반환합니다.
또한, style 속성은 문자열이지만 style 프로퍼티는 객체입니다.
input.checked 프로퍼티의 경우 불린 값을 가집니다.


속성과 프로퍼티 동기화

속성은 다음과 같은 메서드로 다룰 수 있습니다.

  • elem.hasAttribute(name): 속성 존재 여부 확인
  • elem.getAttribute(name): 속성값을 가져옴
  • elem.setAttribute(name, value): 속성값을 변경함
  • elem.removeAttribute(name): 속성값을 지움
  • elem.attributes: 모든 속성과 속성값을 {name:..., value:...} 를 담은 컬렉션으로 반환

표준 속성을 변경하면 이에 대응하는 프로퍼티는 자동으로 갱신됩니다.
몇몇 경우를 제외하고, 프로퍼티를 변경하면 속성 또한 갱신됩니다.

<input>

<script>
  let input = document.querySelector('input');

  // 속성 추가 => 프로퍼티 갱신
  input.setAttribute('value', 'text');
  alert(input.value); // text (갱신)

  // 프로퍼티를 변경해도 속성이 갱신되지 않음
  input.value = 'newValue';
  alert(input.getAttribute('value')); // text (갱신 안됨!)
</script>

위처럼 input 태그의 value 속성의 경우, 프로퍼티를 변경해도 getAttribute 의 결과로 얻어오는 속성은 변하지 않습니다.
(그러나 화면에 보여지는 value 는 변합니다)


dataset 으로 값 전달하기

html 속성에 값을 넣어 활용할 때는 속성 이름을 data-attribute-name 로 지정합니다.
그럼 자바스크립트에서 element.dataset.attributeName 으로 속성을 읽고, 수정할 수 있습니다.

<body data-about-animal="Elephants">
<script>
  alert(document.body.dataset.aboutAnimal); // Elephants
</script>
  • data- 뒤의 문자열은 카멜 케이스로 자동 변환

이 속성은 자바스크립트에서 Write 하는 것도 가능합니다.
자바스크립트 코드에서 특정 엘리멘트에 elem.dataset.someAttr = 10 을 해주면, htmlelemdata-some-attr 속성이 나타나고 속성값이 "10" 으로 지정됩니다.


🔔 문서 수정하기

DOM 을 조작하여 문서에 요소를 생성하는 방법과
기존 콘텐츠를 수정하는 방법을 알아봅시다.


요소 생성하기

DOM 노드를 만들때 다음과 같은 메서드를 사용합니다.

  • document.createElement(tag)
let div = document.createElement('div');

태그 이름을 사용하여 새로운 요소 노드를 생성합니다.


  • document.createTextNode(text)
let textNode = document.createTextNode('안녕하세요.');

텍스트를 사용하여 새로운 텍스트 노드를 생성합니다.


❗요소를 생성했지만, 이는 아직 화면에 나타나지 않습니다.
document 에 넣어주기 전에는 그저 변수에 불과하기 때문입니다.


요소 삽입하기

생성한 노드를 페이지에 보이도록 하기 위해서는 document 어딘가에 포함시켜야 합니다.
이를 위해 삽입 메서드가 존재합니다.

  • element.append(anotherElement)
let div = document.createElement('div');
div.className = "alert";
div.innerHTML = "<strong>안녕하세요!</strong> 중요 메시지를 확인하셨습니다.";

document.body.append(div);

위처럼... body 에 div 를 포함시킬 수도 있고,
다른 element 변수 내에 요소를 넣을 수도 있습니다.


그 외 삽입 메서드의 종류는 다음과 같습니다.

  • node.append(노드나 문자열): 노드나 문자열을 node 내의 끝에 삽입
  • node.prepend(노드나 문자열): 노드나 문자열을 node 내의 맨 앞에 삽입
  • node.before(노드나 문자열): 노드나 문자열을 node 이전에 삽입
  • node.after(노드나 문자열): 노드나 문자열을 node 다음에 삽입
  • node.replaceWith(노드나 문자열): node를 새로운 노드나 문자열로 대체

< appendChild 란 뭘까❓ >

elem.appendChild(node) 메서드는 append 처럼 elem 의 자식 중 
가장 나중 순서에 node 를 추가합니다.
append 와의 차이점은 문자열 값을 받지 못하고 node 만 받을 수 있다는 점과,
추가한 node 를 반환한다는 점입니다.

insertAdjacentHTML 로 HTML 삽입

요소가 아니라 HTML 을 삽입하고 싶다면 elem.insertAdjacentHTML(where, html) 을 사용합니다.
where 에는 elem 에 대한 html 의 상대적 위치를 적으며, 다음 값 중 하나여야 합니다.

  • 'beforebegin': elem 바로 앞에 html을 삽입
  • 'afterbegin': elem 내의 최상단에 html 삽입
  • 'beforeend': elem 내의 최하단에 html 삽입
  • 'afterend': elem 바로 다음에 html을 삽입


노드 삭제하기

node.remove() 로 노드를 삭제할 수 있습니다.

  • node.remove()
document.body.append(div);
setTimeout(() => div.remove(), 1000); // 1초 후 div 가 사라짐

모든 노드 삽입 메서드 (append/prepend/before/after) 는 노드 삭제를 동반하기 때문에,
(기존 노드를 삭제하고 이동) 노드 삽입으로 위치를 바꾸기 전에 굳이 노드 삭제 메서드를 호출할 필요는 없습니다.

< removeChild 란 뭘까❓ >

removeChild 메서드도 remove 처럼 노드를 삭제하는 기능을 수행합니다.
그러나 removeChild 는 부모 노드가 호출하여 자식 노드를 삭제하고,
remove 는 자신을 호출한 대상을 삭제합니다.

node 를 삭제할 때

parentNode.removeChild(node);
node.remove();

이렇게 사용되는 것이죠.

노드 복제하기

cloneNode 로 노드를 복제할 수 있습니다.

  • elem.cloneNode(true): 속성 전부와 자손 요소 전부를 복사하는 깊은 복제본 생성
  • elem.cloneNode(false): 후손 노드 복사 없이 elem 만 복제
let div2 = div.cloneNode(true); // 메시지 창 복제
div2.querySelector('strong').innerHTML = '안녕히 가세요!'; // 복제한 메시지 창 내용 수정

div.after(div2); // 복제한 메시지 창을 기존 메시지 창 다음에 보여줌

DocumentFragment

DocumentFragment 는 특수한 타입의 노드로, 노드 그룹을 감싸는 래퍼처럼 사용합니다.
다른 노드를 DocumentFragment 에 추가한 다음 이를 문서에 삽입하면
DocumentFragment 라는 노드는 문서에 없이 그 안의 노드들만 삽입됩니다.

function getListContent() {
  let fragment = new DocumentFragment();

  for(let i=1; i<=3; i++) {
    let li = document.createElement('li');
    li.append(i);
    fragment.append(li);
  }

  return fragment;
}

ul.append(getListContent());
// 3개의 li 가 ul 안에 삽입됨

요소 삽입 메서드가 여러 개의 인수를 받을 수 있으므로 굳이 사용하는 일은 많이 없습니다.

profile
기록용 블로그 + 오류가 있을 수 있습니다🔥

0개의 댓글