DOM

백승용·2020년 9월 24일

DOM

목록 보기
1/1

HTML이란

  • 웹페이지의 틀을만드는 Markup Language이다.

DOM이란

  • Document Object Model의 줄임말로, HTML 문서의 구조와 관계를 객체로 표현한 모델이다.
  • 트리 구조
    - HTML 문서도, JavaScript 객체도 트리 구조이다.
  • DOM은 프로그래밍 언어는 아니지만 DOM이 없으면 자바스크립트는 웹페이지에 대해 알지 못한다.
  • DOM 없이 자바스크립트로는 HTML을 다룰 수 없다. 자바스크립트에서 DOM을 구현한 document객체를 이용하여 HTML 문서를 조작할 수 있다.
  • 다른 언어도 사용가능하지만 JavaScript를 많이 사용하고 있다.
  • JavaScript를 이용해서 엘리먼트의 속성값을 얻어내거나, 변경하는 방법

DOM 구조를 조회하기

console.dir();

() 안에 document를 넣으면 object의 모습으로 보여준다.
자식 엘리먼트 조회

  • children 속성
    부모 엘리먼트 조회
  • parentElement 속성
document.body.children
document.body.parentElement

DOM을 이용하여 HTML 변경하기

document 객체를 통해서 HTML 엘리먼트를 만들고(CREATE), 조회하고(READ), 갱신하고(UPDATE), 삭제하는(DELETE) 하는 방법을 알아보자.

1. JavaScript에서 요소 생성 (createElement)

  • DOM으로 div를 만들고 자바스크립트의 변수에 할당한다.
  • 하지만 HTML에서는 아무런 변화가 없다. 이유는 요소를 추가하지 않았기 때문이다.
    const tweetDiv = document.createElement('div')

2. append를 사용하여 속성 추가하기 (요소 추가)

  • body에 div 요소를 추가했지만 그래도 아무런 변화가 없다. div 요소는 추가되었지만 내용이 추가되지 않아 안보인다.
	document.body.append(tweetDiv)

.append()

// Inserting a Node object
const parent = document.createElement('div');
const child = document.createElement('p');
parent.append(child);
// This appends the child element to the div element
// The div would then look like this <div><p></p></div>

// Inserting a DOMString
const parent = document.createElement('div');
parent.append('Appending Text');
// The div would then look like this <div>Appending Text</div>

.appendChild()

// Inserting a Node object
const parent = document.createElement('div');
const child = document.createElement('p');
parent.appendChild(child);
// This appends the child element to the div element
// The div would then look like this <div><p></p></div>

// Inserting a DOMString
const parent = document.createElement('div');
parent.appendChild('Appending Text');
// Uncaught TypeError: Failed to execute 'appendChild' on 'Node': parameter 1 is not of type 'Node'

2-1. append vs appendChild

차이점appendappendChild
타입JavaScript 메서드DOM 메서드
반환 값undefinedNode object
여러 요소 추가 가능하나만 노드 객체 추가 가능
DOMStirng과 Node object 추가 가능Node object만 추가 가능
// .append에서 DOMStirng과 Node object 추가 가능하지만 .appendChild는 Node object만 가능
const parent = document.createElement('div');
const child = document.createElement('p');
// Appending Node Objects
parent.append(child) // Works fine
parent.appendChild(child) // Works fine
// Appending DOMStrings
parent.append('Hello world') // Works fine
parent.appendChild('Hello world') // Throws error


//.append()는 여러 요소 추가 가능하지만 .appendChild()는 하나의 Node object만 가능
const parent = document.createElement('div');
const child = document.createElement('p');
const childTwo = document.createElement('p');
parent.append(child, childTwo, 'Hello world'); // Works fine
parent.appendChild(child, childTwo, 'Hello world');
// Works fine, but adds the first element and ignores the rest


// .append()는 반환값이 없고 .appendChild()는 반환값이 Node object이다.
const parent = document.createElement('div');
const child = document.createElement('p');
const appendValue = parent.append(child);
console.log(appendValue) // undefined
const appendChildValue = parent.appendChild(child);
console.log(appendChildValue) // <p><p>

2-2. prepend vs append

prepend : One or more nodes to insert before the first child node currently in the ParentNode.

  • 부모노드의 첫 번째 노드 앞에 노드들을 추가한다.
  • 즉, prepend는 부모 노드의 맨 앞에 append는 부모 노드의 맨 뒤에 추가한다.

Advance

  • appendChild로 기존에 있던 노드를 다른 노드에 추가 시킬 때 기존에 있던 노드는 삭제되는지 아니면 복사되는지 알아보자
<div class="a">
    <span></span>
</div>
<div class="b"></div>
  • span 노드를 class = b인 div에 추가할 때 복사되지 않고 이동된다.
  • 이유는 두개의 부모를 가질 수 없고 ID가 중복된다. 또한, 새로 추가한 노드에 대한 참조가 손실되기 때문이다.
const span = document.querySelector(‘span’); 
const divB = document.querySelector(.b’); 
divB.appendChild(span);

참조 링크

3. JavaScipt에서 DOM을 이용하여 요소 읽기 (querySelector)

<div>HTML Document</div>
<div id = 'div'>HTML Document</div>
<div id = 'div2'>
  <span class = 'span'>HTML Document</span>
</div>
document.querySelector('div');
//결과 : div

document.querySelector('#div');
//결과 : <div id = 'div'>HTML Document</div>

let div = document.querySelector('#div2');
div.querySelector('.span');
//결과 : <span class = 'span'>HTML Document</span>
  • div 요소를 가져온다.
  • .div는 div라는 이름을 가지는 class의 노드를 가져온다.
  • #div는 div라는 이름을 가지는 id의 노드를 가져온다.
  • querySelector() : 한 개의 노드만 읽는다.
  • querySelectorAll() : 여러 개의 노드를 읽는다. 결과값은 유사배열이다.

4. textContent, classList.add (요소 업데이트)

  • 요소에 내용을 추가(textContent, innerHTML)
  • 요소에 class 추가 및 삭제 (classList)
const oneDiv = document.createElement('div') // 요소 생성
console.log(oneDiv) // <div></div>

oneDiv.textContent = 'dev'; // 내용 삽입
console.log(oneDiv) // <div>dev</div>

oneDiv.classList.add('tweet') // class 속성 추가
console.log(oneDiv) // <div class="tweet">dev</div>

const container = document.querySelector('#container') // 부모 엘리먼트
container.append(oneDiv) //append로 요소 추가

4-1. element.classList

<html>
    <head>
        <title>
            안녕~
        </title>
    </head>
    
    <body>
        <div class='divTest'>
            <!-- 내용 시작 -->
            <p class='pTest'>은하수를 여행하는 히치하이커를 위한 안내서</p>
            <p class='pTest'>오리엔트 특급살인</p>
        </div>
    </body>
</html>
  • 읽기 전용 property
document.querySelector('div').classList

//결과 : DOMTokenList ["divTest", value: "divTest"]

let div = document.querySelector('div').classList
//결과 : <div class="divTest"> ... </div>
  • remove() : 클래스 값 제거
div.classList.remove('divTest');
//결과 : <div class> ... </div>
  • add() : 클래스 값 추가
div.classList.add('anotherclass')
// 결과 : <div class='anotherclass'> ... </div>
  • toggle(String, [, force] ) : 인수가 하나일때, 클래스가 존재하면 제거하고 false를 반환하고 존재하지 않으면 클래스를 추가하고 true를 반환한다.
    인수가 두개일때, 두번째 인수가 true로 평가되면 지정한 클래스 값을 추가하고 false로 평가되면 제거한다.
div.classList.toggle('visible');
//결과 <div class=""anotherclass visible"> ... </div>

div.classList.toggle('visible', false);
//결과 <div class="anotherclass"> ... </div>

div.classList.toggle('visible', true);
//결과 <div class="anotherclass visible"> ... </div>
  • contains(String) : 지정한 클래스 값이 엘리먼트의 class 속성에 존재하는지 확인한다.
div.classList.contains('new')
//결과 false
//replace 후는 true
  • replace( oldClass, newClass ) : 존재하는 클래스를 새로운 클래스로 교체한다.
div.classList.replace('anotherclass','new');
// 결과 <div class="new"> ... </div>

4-2. setAttribute()는 속성을 추가하는 것으로 id나 class 등을 생성할 수 있다.

	oneDiv.setAttribute("id","test"); //id="test" 속성을 추가

4-3. textContent vs innerHTML

innerHTML : 태그와 내용 전부다 가져온다. 태그를 넣을 수 있다.

  • innerHTML 사용시 scipt를 보이지 않게 보안에 주의해야한다.
<p id = 'p'><h1 style="color:blue">innerHTML</h1></p>
let p = document.querySelector('#p');
p.innerHTML // <h1 style="color:blue">innerHTML</h1>

textContent : 띄어쓰기와 내용들 전부 가져온다. 값을 재할당 가능하다.

<p id="p"><h1 >textContent</h1></p>
// textContent

참고 링크1
참고 링크2

5. hasChildNodes() 메소드

  • 현재 노드에게 자식노드가 있는지 Boolean값으로 반환합니다.

아래 예시에서는 "foo"라는 id를 가진 요소를 찾고 "foo" 요소에게 자식노드가 있으면 첫번째 자식노드를 제거해줍니다.


let foo = document.getElementById("foo");

if ( foo.hasChildNodes() ) { 
  foo.removeChild( foo.childNodes[0] );
}

6. element.childNodes

  • 자식 노드에 접근하는 방법
  • 현재 요소의 자식 노드가 포함된 NodeList를 반환합니다. 또한, 주석 노드와 같은 비 요소 노드를 포함합니다.
<div>
    <!-- 내용 시작 -->
    <p>은하수를 여행하는 히치하이커를 위한 안내서</p>
    <p>오리엔트 특급살인</p>
</div>

document.querySelector("div").childNodes

// 결과 NodeList(7) [text,comment, text, p, text, p, text]

div 시작 후 엔터가 배열 0번째 요소인 text
내용 시작이 comment
내용 시작 다음 엔터가 text
p는 p 은하수를 여행하는 히치하이커를 위한 안내서
다음 text는 엔터
p는 p 오리엔트 특급살인
다음 text는 엔터
결국,childNodes는
<!-- 내용 시작 -->
<p>은하수를 여행하는 히치하이커를 위한 안내서</p>
<p>오리엔트 특급살인</p>

이다.

7. ParentNode.children

  • 자식 노드에 접근하는 방법
  • 현재 요소의 자식 요소가 포함된 HTMLCollection을 반환합니다. 비 요소 노드는 모두 제외됩니다.
<div>
    <!-- 내용 시작 -->
    <p>은하수를 여행하는 히치하이커를 위한 안내서</p>
    <p>오리엔트 특급살인</p>
</div>

document.querySelector("div").children

// 결과 HTMLCollection(2) [p, p]

7-1. children vs childNodes

8. 요소 삭제하기(remove, removeChild)

  • 노드 추가한 것을 삭제
const body = document.querySelector('body')
const div = document.createElement('div')
body.append(div)
div.remove() 
  • 모든 자식 요소 삭제
const body = document.querySelector('body')
body.innerHTML='' // 자식 엘리먼트 전부 삭제
  • 특정 자식 요소 삭제
const body = document.querySelector('body');
while (body.firstChild) {
  body.removeChild(container.firstChild);
}

9. node vs element

  • node는 DOM에 존재하는 모든 것
  • element는 node 중에 하나이다.

참고 링크1
참고 링크2
참조 링크3


[특정 엘리먼트를 선택하고 가져오기]

  • 태그를 이용: document.getElementsByTagName
  • id를 이용: document.getElementById
  • class를 이용: document.getElementsByClassName
  • selector를 이용: document.querySelector / document.querySelectorAll

버튼 클릭 시 DOM을 이용하여 요소 추가


//p 요소를 body에 javascript를 이용해서 추가해 보기
<body>
<p>요소 하나 추가</p>
</body>
let button = document.querySelector('#button'); // 클릭 이벤트할 요소 가져오기

function buttonInput() { // 요소를 추가하는 함수
  let p = document.createElement('p');
  p.textContent="요소 하나 추가";
  
  let parent = document.querySelector("body");
  parent.appendChild(p);*- 
}

button.addEventListener('click',buttonInput); //클릭 이벤트 발생 시 이벤트 핸들러 사용
button.onclick = buttonInpu;
  

엘레먼트 객체
|속성 이름|속성|
|:---:|:---:|
|tagName | 태그 이름|
|id | id값|
|classList | class 목록|
|className | class 문자열|
|value | form 입력값|
|children|자식 엘리먼트|
|parentElement|부모 엘리먼트|
|childNodes|자식 노드|
|dataset|실제 데이터는 아니지만 속성에 담아있는 값|
|onclick|클릭 이벤트|

vanilla 링크

prototype을 이용하여 메서드 만들기


/* this가 number형인 값을 불러와 함수 작성 가능 */
Number.prototype.[메서드 이름] = function() {
//...함수 실행할 명령어들
}

template tag를 이용하여 요소를 보여주고 싶은 것만 보여주기

  • template 사용 목적 : 자바스크립트에서 반복적으로 요소 생성, 내용 추가, 클래스 및 id를 추가하지 않도록 사용하기 위해서 HTML에서 template를 작성한다.
  • template를 사용하면 안에 있는 요소가 보여지지 않는다.
<template id='a'>
  <span>after</span>
</template>

<div id='b'>before</div>
let b = document.querySelector('#b');
let template = document.querySelector('#a');

let newContent = document.importNode(template.content,true);
// 자식 노드 전부 포함하여 복사

b.textContent = '';
b.appendChild(newContent); //<div id='b'>after</div>

DOM 너~무 어렵다 ㅠㅠ

0개의 댓글