TIL 13일차

ᄋᄋ·2021년 12월 12일
0

*DOM standard 사이트

DOM

Web을 build 하기 위해 JS(ECMAScript), DOM, BOM이 존재함.

Web API

  • DOM : 문서 객체를 다루기 위한 속성, 메소드 제공.
  • BOM : 브라우저 객체를 다루기 위한 속성, 메소드 제공.

브라우저는 DOM이라는 규칙을 사용해 HTML 파일을 렌더링함.

DOM(Document Object Model)의 개념

DOM은 프로그래머 관점에서 바라 본 HTML으로, HTML 문서의 구조와 관계를 객체로 표현한 모델.

따라서 HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model임. 이때 document라는 전역변수(객체)로 HTML(root document)에 접근함.

HTML 문서, JS 객체 둘 다 트리 구조임.

+참고) BOM(Browser Object Model)은 window 객체를 통해 브라우져에 접근함.

HTML에서 Javascript 파일을 불러올 때 주의점

HTML에 JavaScript를 적용하기 위해서는 <script> 태그를 이용함.

<script src="myScriptFile.js"></script>

웹 브라우저가 작성된 코드를 해석하는 과정에서 <script> 요소를 만나면, 웹 브라우저는 HTML 해석을 잠시 멈춤. 이때 <script> 요소를 먼저 실행함. 즉, <script> 요소는 등장과 함께 실행됨.

<script> 태그를 추가하는 두 가지 대표적인 방법

  • <head> 태그에 추가하는 방법
  • </body> 가 끝나기 전에 추가하는 방법

이때 <script> 태그가 적용되는 위치에 따라서 실행 결과가 달라질 수 있음.
<head> 태그에 추가하는 경우, 브라우저가 html을 읽다가 script를 만나면 html 파싱을 잠시 중단하고 script를 실행시킴. 이때 script 코드에서 html 요소에 대한 동작 코드가 있으면,
예를 들어 html 요소 중 #msg를 선택자로 갖는 요소를 출력하라는 스크립트 동작을 실행해야 할 때, 그 요소를 브라우저가 아직 읽지 못 했기 때문에 해당 요소가 출력되는 대신 null 값이 출력되는 일이 생김. 반면 body 태그 끝에 script 태그를 추가하는 경우, html 파싱을 다 끝내고 난 후에 script를 실행시키기 때문에 html 요소에 대한 동작 코드들이 정상적으로 잘 실행됨.

  • 파싱(한 줄 한 줄 읽기)
  • fetching(다운로드 받아서 읽어내림)
  • executing(실행)
  • 위의 과정을 거치는 게 렌더링.

console.dir

DOM 구조를 조회할 때에는 console.dir이 유용함.
console.dirconsole.log와 달리 DOM을 객체의 모습으로 출력함.

Q1. body 엘리먼트의 자식 엘리먼트(element) 찾기
console.dir(document.body): body 요소를 객체처럼 보여줌.

객체의 속성들 중 children이 있음.

여기에 자식 요소가 총 3개라고 나옴.

document.body.children으로 찾으면 바로 해당 요소들을 찾을 수 있음.


Q2. id의 이름이 news-contents 인 div 엘리먼트의 부모 엘리먼트 찾기
document.body.children[1]은 id가 news-contents인 div 엘리먼트임.

변수 선언을 해서 이 정보를 저장해두면, 주소를 참조하기때문에 언제든지 접근할 수 있음.

속성들 중 parentElement 속성도 있는데, 여기서는 그 값이 body임.

DOM의 구조


이런 자료 구조를 컴퓨터 공학에서는 트리 구조라고 함. 트리 구조의 가장 큰 특징은 부모가 자식을 여러 개 가지고, 부모가 하나인 구조가 반복된다는 점임.

DOM을 JavaScript로 조작하여 HTML Element를 추가하거나 삭제, 혹은 내용을 변경할 수 있음. (CRUD + APPEND)

document 객체를 통해서 HTML 엘리먼트를 만들고(CREATE), 조회하고(READ), 갱신하고(UPDATE), 삭제(DELETE)할 수 있음. 또한 DOM에는 HTML에 적용(APPEND)하는 메소드도 있음.

createElement - CREATE

새로운 element를 만듬.

document.createElement('div')   // 이걸 변수에 할당하면 
const tweetDiv = document.createElement('div')

createElement 메소드로 생성된 엘리먼트는 공중에 떠있는 상태임.
공중에 떠있는 엘리먼트를 확인하기 위해서는 APPEND 해야함.

appendChild - APPEND

document.body.append(tweetDiv)

변수 tweetDiv에 담긴 새로운 div 엘리먼트를 body 엘리먼트에 append 함.
이때 textContent 메소드를 활용하면 div 안에 내용을 넣을 수 있음.

그런데 생성한 tweetDiv를 container에 넣는다면?
일단 container를 먼저 찾아야 함.

querySelector, querySelectorAll - READ

DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(Selector)를 전달하여 확인할 수 있음.

셀렉터로는 HTML 태그("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용됨.

const oneTweet = document.querySelector('.tweet')
//클래스 이름이 tweet인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회할 수 있음.

여러 개의 엘리먼트를 한 번에 가져오기 위해서는, querySelectorAll을 사용함.

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

이렇게 조회한 HTML 엘리먼트들은 배열처럼 for 문을 사용할 수 있음.
하지만 이런 배열은 Array-like Object(유사 배열 또는 배열형 객체)임.

get 으로 시작하는 DOM 조회 메소드도 있음(오래된 방식).

const getOneTweet = document.getElementById('container')
const getOneTweet = document.getElementsByClass('tweet')

tweetDiv를 container에 넣기 (append)

const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')

container.append(tweetDiv)
//tweetDiv를 container의 마지막 자식 요소로 추가함.

textContent, id, classList, setAttribute - UPDATE

textContent를 사용해서, 비어있는 div 엘리먼트에 문자열을 입력함.

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

CSS 스타일링이 적용될 수 있도록, div 엘리먼트에 class를 추가함.

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

append를 이용해 container의 자식 요소로 추가함.

class와 id 말고, 다른 attribute를 추가하려면 setAttribute 메소드 사용하면 됨.
Element.setAttribute(속성이름, 속성값);

DELETE : remove, removeChild, innerHTML = "" , textContent = ""

삭제하는 방법에도 여러 가지가 있음.
먼저 삭제하려는 엘리먼트의 위치를 알고 있는 경우에 사용하는 방법임. remove

--remove--
const container = document.querySelector('#container')
const tweetDiv = document.createElement('div')
container.append(tweetDiv)
tweetDiv.remove()     

여러 개의 자식 엘리먼트를 지우려면?
innerHTML을 이용

--컨테이너의 모든 자식 엘리먼트를 지우기--
document.querySelector('#container').innerHTML = '';

그런데 innerHTML은 보안에서 몇 가지 문제를 가지고 있음.
<script> tag를 활용하여 강제로 해커가 원하는 스크립트를 실행시키는 XSS Attack이 대표적임.

이 방법을 대신할 다른 메소드는 removeChild임.
자식 엘리먼트를 지정해서 삭제하는 메소드임.
모든 자식 엘리먼트를 삭제하기 위해, 반복문(while, for, etc.)을 활용할 수 있음.

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

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

그런데 이렇게 삭제하면 제목에 해당하는 h2 "Tweet List"까지 삭제됨.

이를 방지하기 위한 방법은 여러 가지가 있음.
(1)자식 요소가 담고 있는 문자열을 비교해 "Tweet List"만 남기거나,
(2)새로운 변수를 생성하고 Tweet List를 할당해뒀다가 반복문이 끝난 뒤에 새롭게 추가할 수도 있음.
또는 (3)자식 엘리먼트를 하나만 남기게 할 수도 있음.

(3)번 방식
const container = document.querySelector('#container');
while (container.children.length > 1) {
  container.removeChild(container.lastChild);
}

또는 (4)직접 클래스 이름이 tweet인 엘리먼트만 찾아서 지우는 방법도 있음.

const tweets = document.querySelectorAll('.tweet')
tweets.forEach(function(tweet){
    tweet.remove();
})
// or
for (let tweet of tweets){
    tweet.remove()
}

  • document.cloneNode는 복제하는 메소드임.
    이 메서드를 호출한 Node의 복제된 Node를 반환함.
var dupNode = node.cloneNode(deep);

node : 복제되어야 할 node.
dupNode : 복제된 새로운 node.
deep (Optional): 해당 node의 children까지 복제하려면 true, 해당 node만 복제하려면 false
  • document.importNodetemplate을 활용하여 내용을 붙여넣을 때 사용하는 메소드임.
    현재 문서가 아닌 외부 문서의 노드를 복사하여 현재 문서에 넣을 수 있도록 해줌.
var node = document.importNode(externalNode, deep);

node : 문서에 추가될 새로운 노드임. 새로운 노드가 문서 트리에 추가되기 전까지, 새로운 노드의 parentNode는 null임.
externalNode : 다른 문서에서 가져올 노드임.
deep : 불리언 타입을 가지며, 다른 문서에서 노드를 가져올 때 노드의 자식 요소들을 포함하여 가져올 것인지에 대한 여부를 결정함. 

  • insertBefore : 부모노드.insertBefore(삽입 할 노드, 기준점 노드);
    기준점 노드 앞에 삽입됨. 만약 없으면 맨 끝에 삽입.

  • insertAfter : 위와 비슷한데 기준점 노드 뒤로 삽입함.

  • prependChild : 부모 노드에 첫번째 자식 위치로 추가. 하나의 요소만 추가 가능.

  • appendChild : 부모 노드 마지막 자식 위치로 추가. 하나의 요소만 추가 가능. +prepend / append는 여러 요소를 추가할 수 있음.


  • innerHTML과 textContent의 차이

    • innerHTML은 string을 parsing해 엘리먼트로 변환하여 집어넣는 속성.
      해당 요소의 자식 요소들의 html 태그까지 포함.
      (띄어쓰기가 포함되어 나옴.)

    • textContent는 엘리먼트 내 content 부분에 text만 넣어주는 메소드.
      (띄어쓰기가 포함되어 나옴.)

  • createDocumentFragment를 활용하여, 더 효율적으로 DOM을 제어.

    var docFragment = document.createDocumentFragment();
    docFragment는 빈 DocumentFragment 객체를 나타냄.

    미리 메모리상에 특정 노드의 형태를 생성한 후에, 그 노드를 실제 DOM에 추가해서 사용하고 싶을 때 추가하면 실제로 적용됨. 메모리상에서만 존재할 때는 적용이 안 된 상태이므로 아무런 존재감이 없음.

profile
개발자A

0개의 댓글