[JavaScript/브라우저] DOM

Hyun Jin·2023년 1월 5일
0

JavaScript

목록 보기
12/20

DOM(Document Object Model)

1. 정의


DOM(Document Object Model), 즉 문서 객체 모델은 메모리에 웹 페이지 문서의 구조화된 표현(tructured representation)을 제공하며, 프로그래밍 언어가 DOM 구조에 접근 및 변경할 수 있게 돕는다.
DOM 으로 HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation) 가능하다.

DOM은 문서를 논리 트리로 표현한다. 트리의 각 브랜치는 노드에서 끝나며, 각 노드는 객체(object)를 담고 있다. DOM 메서드를 사용하면 프로그래밍적으로 트리에 접근해서 문서의 구조, 스타일, 콘텐츠를 변경할 수 있다.

노드는 태그, element, text, 주석 등을 포함하고, 이벤트 처리기도 포함할 수 있다. 이벤트가 발생한 순간 해당 이벤트와 연결한 처리기가 발동한다.


이미지 출처: https://www.tutorialstonight.com/what-is-a-node-in-javascript


+) 참조 사이트

DOM Living Standard
W3C - DOM Specification

+) 더 알고 싶은 것 : node, shadow DOM tree, what is good DOM structure, 브라우저에서 DOM tree 를 생성하는 단계, 렌더링 경로 최적화, 적정 DOM 사이즈, DOM 사이즈의 한계, DOM 사이즈 확인방법, Namespaces...


2. DOM 접근법


각각의 브라우저는 자신만의 방법으로 DOM 을 구현하고 있다.
script 를 작성할 때 documentwindow object* 를 바로 사용할 수도 있고, 그 외 다른 함수를 사용하여도 javascript 에서 접근이 가능하다.

  • window object 는 브라우저, document object 는 root document 자체와 같다고 할 수 있다.
    console.dir(document.body.children[1]) 으로 document.body.children 의 1번째 인덱스의 요소를 조회할 수 있다.

1. 생성(CREATE) :  .createElement

🔗 MDN - Document.createAttribute()

Document.createAttribute() 메소드는 새로운 attribute node를 만들고 리턴한다. 생성된 object 는 Attr 인터페이스를 구현하는 노드이다. 이 방식에서 DOM 은 어떤 종류의 attributes가 element 에 추가될 수 있는지 강제하지 않는다.

  • 구문 :
createAttribute(name)
  • 예시 :
document.createElement('div')
const makeDiv = document.createElement('div') // 변수에 할당해 놓으면 편하다.

2. 추가(APPEND) :  .append()

🔗 MDN - Document.append()

Document.append() 메소드는 문서의 last child 요소 뒤에 Node 나 string objects 를 추가한다.
이 메소드는 Document 에 child 를 추가한다. (element 를 DOM tree 에 추가하고 싶으면 Element.append()* 를 참조)

  • 구문 :
append(param1)
append(param1, param2)
append(param1, param2, ...paramN)
  • 예시 :
document.body.append(makeDiv)
  • Return value : None (undefined).

+) 특정 부모 노드 안에 요소를 append 하려면 -> .appendChild() 사용!
특정 부모 요소의 children 리스트 맨 끝에 해당 자식 node 를 추가하는 메소드.
해당 자식 node 가 문서 안에 존재하는 경우, 현재 위치에서 새로운 위치로 이동시킨다.
노드가 이미 부모요소를 가지고 있을 경우, 우선 삭제되고 새로운 위치로 이동한다.

  • appendChild() 예시 :
// Create a new paragraph element, and append it to the end of the document body
const p = document.createElement("p");
document.body.appendChild(p);
  • Return value : 추가된 child node("p") 를 반환. 단 DocumentFragment* 일 경우 empty DocumentFragment 반환.

3. 조회(READ) :  .querySelector, querySelectorAll

🔗 MDN - Document.querySelector()

.querySelector(), .querySelectorAll()

DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있습니다. 셀렉터로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용됩니다.

  • querySelectorAll 은 유사배열(Array-like Object, 배열처럼 for 문을 사용 가능)

*getElementById, getElementsByClass 는 querySelector 비슷한 역할을 하는 오래된 방식.

+) 특정 부모 노드 하위의 노드를 검색 시, 여러 개의 노드가 조회될 경우에는 유사 배열 형태인 HTMLCollection 형태로 반환됨.

+) childNodes, firstChild, lastChild로 자식 노드 탐색하기


4. 변경(UPDATE) :  .textContent, .classList.add, .setAttribute...

1. .textContent

const oneDiv = document.createElement('div');
console.log(oneDiv) //


oneDiv.textContent = 'dev';
console.log(oneDiv) //
dev

2. .classList.add

oneDiv.classList.add('tweet')
console.log(oneDiv) //

dev

*? class와 id 말고는 다른 attribute를 추가할 수는 없나요?-> setAttribute 검색해보기!

Lower casing, Non-existing attributes => null,

.setAttribute(name, value) ->

예시)
const button = document.querySelector("button");

button.setAttribute("name", "helloButton");
button.setAttribute("disabled", ""); // true

+) getAttribute()

Hi Champ!

//JS
const exampleAttr = div1.getAttribute('id');
//=> "div1"

+) removeAttribute()
removeAttribute(attrName)
// attrName = string. 존재하지 않아도 에러를 내지 않고 아무 동작도 하지 않음.

Return value
None (undefined).


### 5. 삭제(DELETE) :  .remove(), .innerHTML, .removeChild

1) .remove()

삭제하려는 요소의 위치를 알고 있는 경우

const container = document.querySelector('#container')

const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove() // 이렇게 append 했던 요소를 삭제할 수 있다.

2) .innerHTML

여러개의 자식 요소를 지우려고 하는 경우

document.querySelector('#container').innerHTML = '';

*)+ innerHTML 의 보안 문제점
https://developer.mozilla.org/en-US/docs/Web/API/Element/innerHTML#security_considerations

3) .removeChild

자식요소를 지정해서 삭제하기. 모든 자식요소를 삭제하기 위해 반복문(while, for 등)을 활용할 수 있음.

const container = document.querySelector('#container');

while (container.firstChild) {
container.removeChild(container.firstChild);
}

removeChild 와 while 을 이용해 자식 요소를 삭제하면, 제목에 해당하는 H2 "Tweet List"까지 삭제됩니다. 이를 방지하기 위한 방법은 여러 가지가 있습니다. 자식 요소가 담고 있는 문자열을 비교해 "Tweet List"만 남기거나, 새로운 변수를 생성하고 Tweet List를 할당해뒀다가 반복문이 끝난 뒤에 새롭게 추가할 수도 있습니다. 또는 자식 요소를 하나만 남기게 할 수도 있습니다.

const container = document.querySelector('#container');

while (container.children.length > 1) {
container.removeChild(container.lastChild);
}
[코드] container의 자식 요소가 1개만 남을 때까지, 마지막 자식 요소를 제거합니다.

또는 직접 클래스 이름이 tweet인 요소만 찾아서 지우는 방법도 있습니다.

const tweets = document.querySelectorAll('.tweet')

tweets.forEach(function(tweet){
tweet.remove();
})
// or
for (let tweet of tweets){
tweet.remove()
}



📚 추가 학습


Element.append()*

🔸 Document.append() 와 다른 특징 3가지 : string objects 추가 가능, return value 없음, 여러개의 nodes 나 strings 추가 가능.(되지 않나? 추가로 찾아볼 필요 있음.)

❗️ DocumentFragment*, Document.createDocumentFragment()* :

🔸 Reflow, Repaint : append() 등 DOM 을 조작하거나 접근하는 경우 Reflow 및 Repaint 가 발생하며, 대량으로 조작하거나 접근하는 경우 웹 페이지의 성능을 저하시킴.

🔸 DocumentFragment 객체 : DOM 요소를 저장하는 임시 저장소. 기본적으로 DOM 과 동일하게 동작하지만, HTML 의 DOM tree에는 영향을 주지 않으며, 메모리에서만 정의됨.

🔸 DocumentFragment 객체는 DOM 트리의 일부가 아니므로 수정 및 변경이 발생해도 웹 페이지에 영향을 미치지 않음. 그래서 DocumentFragment 객체를 조작 후 DOM 트리에 DocumentFragment 객체를 추가하면, 한 번의 Reflow만 발생하여(==단 한번만 DOM 에 접근하고 같은 결과를 가져와서) 웹페이지 성능을 개선할 수 있음.

🔸 성능 비교 : CreateElement로 만든 루트 노드 삽입과 Fragment 객체 하위 트리의 DOM 삽입은 성능상 큰 차이가 있는지 불분명하고, 메모리 누수가 있을 수도 있음.

🔗 참고사이트 :
DocumentFragment객체 사용 방법
DocumentFragment객체는 무엇이며 왜 써야 할까?

Virtual Dom (→ 검색하다 발견했는데, 이건 react 배우면서 배울 것 같음!)

🔗 참고사이트 :virtual dom이 뭐가 좋은가?

❗️

+) 다른 Array-like Object 은 어떤게 있는지 찾아보자!

profile
새싹 프론트엔드 개발자

0개의 댓글