DOM (Document Object Model)

shleecloud·2021년 8월 8일
0

시작

DOM, Document Object Model. 어렵다고 듣기만 하다가 막상 접하니 처음 느낀 감정은 낯설음이었다. 그동안 접할 기회가 없었던 객체와 메소드와 속성값이 계속 튀어나온다. 하지만 논리적인 어려움은 아니라서 반복해서 사용하고 익숙해지면 될 문제다. 이런건 어렵다고 표현하기 보다는 낯설다고 표현하는게 맞다고 본다. 어렵지는 않았다. 내용이 방대해서 모든 내용을 정리할 수는 없지만 핵심 개념과 자주 등장하는 기능을 정리하고자 한다.


용어 정리

DOM

DOM (Document Object Model) 은 HTML 또는 XML (en-US) document와 상호작용하고 표현하는 API입니다. DOM은 browser에서 로드되며, 노드 트리(각 노드는 document의 부분을 나타냅니다)로 표현하는 document 모델입니다(예, element, 문자열, 또는 코멘트).

웹문서를 받으면 브라우저 렌더링 엔진에서 브라우저가 해석할 수 있게 DOM 형태로 메모리에 적재한다. 그리고 DOM API를 통해서 프로그래밍 언어(javascript)로 실시간으로 제어할 수 있다.

노드

Node는 여러 가지 DOM 타입들이 상속하는 인터페이스이며 그 다양한 타입들을 비슷하게 처리할 수 있게 한다. 예를들어, 똑같은 메소드를 상속하거나 똑같은 방식으로 테스트를 할수있다

  • 문서 노드(Document Node)트리의 최상위에 존재하며 각각 요소, 어트리뷰트, 텍스트 노드에 접근하려면 문서 노드를 통해야 한다. 즉, DOM tree에 접근하기 위한 시작점(entry point)이다.
  • 텍스트 노드(Text Node)텍스트 노드는 HTML 요소의 텍스트를 표현한다. 텍스트 노드는 요소 노드의 자식이며 자신의 자식 노드를 가질 수 없다. 즉, 텍스트 노드는 DOM tree의 최종단이다.
  • 요소 노드(Element Node)요소 노드는 HTML 요소를 표현한다. HTML 요소는 중첩에 의해 부자 관계를 가지며 이 부자 관계를 통해 정보를 구조화한다. 따라서 요소 노드는 문서의 구조를 서술한다고 말 할 수 있다. 어트리뷰트, 텍스트 노드에 접근하려면 먼저 요소 노드를 찾아 접근해야 한다. 모든 요소 노드는 요소별 특성을 표현하기 위해 HTMLElement 객체를 상속한 객체로 구성된다.
  • 어트리뷰트 노드(Attribute Node)어트리뷰트 노드는 HTML 요소의 어트리뷰트를 표현한다. 어트리뷰트 노드는 해당 어트리뷰트가 지정된 요소의 자식이 아니라 해당 요소의 일부로 표현된다. 따라서 해당 요소 노드를 찾아 접근하면 어트리뷰트를 참조, 수정할 수 있다.

엘리먼트(요소)

엘리먼트는 태그로 시작해서 태그로 끝난다.

엘리먼트는 다른 표현으로 엘리먼트 노드라고 부른다. 노드는 엘리먼트의 상위 개념이다.


DOM 조작

1. 새 엘리먼트를 만든다.

let li = document.createElement('LI'); // 태그명은 대문자 

2. 엘리먼트에 내용을 추가한다.

li.className = 'comment';
li.textContent = '반갑습니다';

3. 삽입하려는 부모 엘리먼트를 선택해서 가져온다.

let parent = document.querySelector('#view-comments');

4. 부모 엘리먼트에 새 엘리먼트를 추가한다.

parent.appendChild(li)

5. 삭제

li.remove();

자주 사용하는 기능

DOM 구조 조회 console.dir()

  • console.log는 요소를 HTML과 같은 트리 구조로 출력합니다.
  • console.dir은 요소를 JSON과 같은 트리 구조로 출력합니다.

구체적으로, console.log는 DOM 요소에 대해 특별한 처리를 제공하지만 console.dir은 그렇지 않습니다. 이것은 종종 DOM JS 객체의 전체 표현을 보려고 할 때 유용합니다.

className & classList

  • className 문자열 변수는 class 목록을 문자열로 반환함 "comment hello world"
> elIdFailureFirstCharEng.className
< "id-failure-first-char-eng hide"
> elIdFailureFirstCharEng.className.length // 클래스 길이를 돌려주지 않음 
< 30
  • classList 메소드는 class 목록을 유사 배열로 반환함 ["comment", "hello", "world"]
    자세한 내용은 DOMTokenList 참조
> elIdFailureFirstCharEng.classList
< DOMTokenList(2) ["id-failure-first-char-eng", "hide", value: "id-failure-first-char-eng hide"]
> elIdFailureFirstCharEng.classList.length
< 2

Value

input 태그의 있는 value 속성 값을 받아올 수 있음.

이 엘리먼트에 이벤트 리스너를 설치하면 입력할 때 마다 이벤트를 발생시키는 기능을 구현할 수 있음.

elInputUsername.onkeyup = function () {
  if (isMoreThan4Length(elInputUsername.value)) {
    elFailureMessage.classList.add('hide');
    elSuccessMessage.classList.remove('hide');
  } else {
    elSuccessMessage.classList.add('hide');
    elFailureMessage.classList.remove('hide');
  }

이벤트 (onclick, onmouseover, onkeyup 등)

// 특정 이벤트를 지울 수 있음
window.addEventListener('resize', console.log('resize1'))

// 모든 이벤트를 지워야 함
window.onresize = function () { console.log('window resize') }
  • addEventListner 방식은 여러개의 이벤트를 할당할 수 있고 특정 이벤트만 삭제할 수 있어서 자주 사용함
  • 이벤트 버블링은 자식 엘리먼트에서 발생한 이벤트 리스너가 부모와 조상 엘리먼트의 리스너까지 발동시키는 현상이다. third를 클릭할 경우 second 그리고 first 순서로 클릭 이벤트가 발생한다.
    <div id="first"><div id="second"><div id="third"></div></div></div>

추후 참조 URL : https://www.zerocho.com/category/JavaScript/post/57432d2aa48729787807c3fc
이벤트 버블링, 콜백 함수

innerHTML, innerText, textContent

  • innerHTML
    HTML 모든 요소가 포함되기 때문에 HTML 통째로 내용을 바꿀 수 있음
    보안 취약점이 될 수 있음 XSS(크로스 사이트 스크립팅). SQL Injection과 비슷함. 필터를 통해서 차단 가능
  • innerText (잘 안씀)
    문자열 부분만 가져옴
    값을 변경할 수 없음. 만약 값을 변경할 경우 텍스트만 남긴채 관련된 엘리먼트를 모두 없앰
    display:none 으로 지정되어 보이지 않는 문자는 가져오지 않음. CSS 종속적.
  • textContent
    텍스트가 아닌 요소들이 모두 공백으로 바뀌어서 포함됨
    하나의 단일 엘리먼트에 값을 입력하거나 변경할 때 주로 활용
    display:none 으로 지정된 문자도 가져옴
$0.innerText
"유효성 검사\n아이디\n비밀번호\n비밀번호 확인"
$0.innerHTML
"\n  유효성 검사\n  <!-- 동영상 강의에 나온 코드를 그대로 실습하세요 -->\n  <div>아이디</div>\n  <input type=\"text\" name=\"username\" id=\"username\">\n  <div class=\"success-message hide\">사용할 수 있는 아이디입니다.</div>\n  <div class=\"failure-message hide\">아이디는 네 글자 이상입니다.</div>\n - 중략"
$0.textContent
"\n  유효성 검사\n  \n  아이디\n  \n  사용할 수 있는 아이디입니다.\n  아이디는 네 글자 이상입니다.\n  영어와 숫자만 입력할 수 있습니다.\n  첫 글자는 영어만 입력할 수 있습니다.\n  비밀번호\n  \n  비밀번호 확인\n  \n  비밀번호가 일치하지 않습니다.\n  비밀번호가 8자리 이상, 특수문자 대소문자 하나씩 포함해야 합니다.\n  첫 글자는 영어만 입력할 수 있습니다.\n  \n\n"

children(자식 엘리먼트) vs childNode(자식 노드)

예제 HTML

<body>
  <div>
    여기 글자 있습니다.
    <span>자식도 있습니다.</span>
    <span>자식도 여럿 있습니다.</span>
  </div>
</body>

예제 JS

$0.children
HTMLCollection(2) [span, span]
$0.childNodes
NodeList(5) [text, span, text, span, text]

$0.childNodes.forEach( function(value, key) {
console.log(key + ' / ' + value.textContent);})
0 / 
    여기 글자 있습니다.
    
1 / 자식도 있습니다.
2 / 
    
3 / 자식도 여럿 있습니다.
4 /

// text(여기 엘리먼트 있습니다. <또는 공백>) + span(자식도 있습니다.) + text(공백) + span(자식도 여럿 있습니다.) + text(공백)
  • children 메소드는 엘리먼트를 돌려줌
    태그로 둘러쌓여진 span을 반환
  • childrenNodes 메소드는 모든 노드를 돌려줌
    텍스트 내용과 엘리먼트가 섞여 있을 때 사용할 수 있음
    만약 여기 엘리먼트 있습니다. 라는 텍스트가 없었으면 공백으로 판단한다.
    공백은 노드다. 공백은 엘리먼트가 아니다.

Dataset

예제 HTML

<div data-user="steve" data-role="moderator" data-user-id="1">
	Steve Lee
<div>

예제 JS

$0.dataset.user // 'steve'
$0.dataset.role // 'moderator'
$0.dataset.userId // '1'

dataset을 활용해서 HTML 속성에 data- 로 시작하는 숨겨진 속성을 넣고 dataset. 노드로 제어할 수 있음

appendChild

특정 엘리먼트를 자식 엘리먼트에 추가하는 메소드.
이 동작은 이동을 일으킨다. 이전 위치에선 없어지게 된다.

append 동작으로 복사하지 않는 가장 큰 이유는 span 변수가 가리키는 인스턴스가 이전 또는 복사된 인스턴스가 될 것이다. 이 경우 하위 트리가 깊을 경우 직관적이지 못하다.

<div class="a">
  <span></span>
</div>
<div class="b"></div>
const span = document.querySelector(‘span’); 
const divB = document.querySelector(.b’); 
divB.appendChild(span);
<div class="a"></div>
<div class="b">
  <span></span>
</div>

https://indepth.dev/posts/1161/here-is-why-appendchild-moves-a-dom-node-between-parents

추가 문서

DOM 엘리먼트 선택

DOMTokenlist

참조 URL

profile
블로그 옮겼습니다. https://shlee.cloud

0개의 댓글