TIL #0408

Adela·2020년 4월 8일

✍Today I Learned

목록 보기
9/15
post-thumbnail

DOM : Document Object Model

JavaScript를 이용해서 HTML 엘리먼트의 속성값을 얻어내거나 변경하는 방법
DOM은 웹 페이지의 객체 지향적인 표현이다.
자바스크립트와 같은 스크립팅 언어를 이용해 DOM 을 수정할 수 있다.

브라우저의 동작 원리

HTML 마크업 파싱 -> DOM 트리 빌드
CSS 마크업 파싱 -> CSSOM (CSS객체모델) 트리 빌드

DOM 및 CSSOM의 결합 => 렌더링 트리 생성

렌더링 트리에서 레이아웃을 실행 -> 각각의 노드들의 레이아웃을 계산 ->
노드들을 화면에 렌더링

HTML 구성

<body>
  <div id='practice' class='highlight red'>
    여기 엘리먼트가 하나 있습니다
    <span>ㅇㅇㅇ</span>
    <span>ㅋㅋ</span>
  </div>
</body>
  • 속성: <>안에 태그 이름과 같이 정의되어 있는 것

  • 태그이름: body, div, span

  • id: practice

  • class: highlight, red

  • 안쪽에 담긴 내용: 여기 엘리먼트가 하나 있습니다, ㅇㅇㅇ, ㅋㅋ

  • div#practice 에 대하여

  • 부모엘리먼트: body

  • 자식엘리먼트: span, span

Document를 Object처럼 조작하고, 이벤트를 적용하는 방법

html은 tree구조를 갖는다.

javascript에서 tree구조를 갖는 것은 객체 Object

key의 값value으로 또 다른 object(배열 & 객체)를 가질 수 있다.

🚫 DOM이 JavaScript는 아니다.
DOM 구조 접근에 JavaScript를 이용한다는 것이다.

따라서 DOM:Document Object Model이란?
📌 HTML 문서의 구조와 관계를 객체(Object)로 표현한 것
document라는 전역변수로 접근이 가능

{
  tagName: 'DIV',
  id: 'practice',
  classList: ['highlight', 'red'],
  textContent: '여기 엘리먼트가 하나 있습니다 ㅇㅇㅇ ㅋㅋ',
  parentElement: body,
  children: [
    {tagname: 'SPAN',
     textContent: 'ㅇㅇㅇ'
    },
    {tagname: 'SPAN',
     textContent: 'ㅋㅋ'
    }
  ]
}
console.log(document);
// html이 구조로 나옴 `<head><body>...`
console.dir(document);
// element를 확인할 수 있는 방법, html이 object처럼 나옴

// charset:~~이 궁금하다면? 실제로 js에서 찍어볼 수 있다.
document.charset;  //'UTF-8'

엘리먼트에 담긴 내용을 볼 수 있는 속성

$0은 크롬개발자도구 콘솔창에서 HTML속성을 확인해볼 수 있는 방법이다.
코드 내에서 아래 키워드들로 속성을 확인하려면, 해당 엘리먼트를 변수로 선택하고(🔎 특정 element를 선택하고 가져오는 법)
console.log(변수명)/ console.dir(변수명) 하면 된다.

태그이름 tagName : $0.tagName
id selector : $0.id
class목록 classList :$0.classList
class문자열 className : $0.className
속성 객체 attributes : $0.attributes

<div class='contents'> 안녕 ???</div> ==$0
innerText 비교적 사용이 적음 안녕 ???
실제로 화면에 랜더링되는 text들이 보여짐

엘리먼트에 담긴 내용 innerHTML : $0.innerHTML

  • 안녕 ???

HTML요소의 값을 바꾸거나 값을 넣을 때
값을 할당할 수 있고 실제로 화면의 내용을 바꿀 수 있다.

화면에 실제로 해당태그위치에
$0.innerHTML="<a href = 'https://velog.io'>벨로그</a>"하면
벨로그가 된다

부모태그에서 사용시 관련tags<> 가 전체적으로 보여짐

엘리먼트에 담긴 내용 textContent : $0.textContent 안녕 ???
하나의 단일 element에 내용을 채워넣을 때 사용
값을 할당할 수 있고 실제로 화면의 내용을 바꿀 수 있다.

innerHTML과의 차이점
$0.textContent="<a href = 'https://velog.io'>벨로그</a>"하면
위의 태그가 그대로 화면에 문자열 자체로 추가된다.

랜더링된 화면이 아니라 실제 포함되어있는 공백까지 텍스트와함께 보여짐

value: $0.value
form 입력 값을 얻을 수 있다.
form 입력창 =>id입력창,댓글입력창,input,textarea,,,에 입력값이 들어오면 $0.value를 통해 입력값을 얻는다.
ex) twittler만들 때 새글 쓰기

부모 element parentElement : $0.parentElement
자식 element vs 자식 node

<body>
  <div id = 'practice' class = 'highlight red'>
    여기 엘리먼트가 하나 있습니다
    <span>ㅇㅇㅇ</span>
    <span>ㅋㅋ</span>
  </div>
</body>
  • 여기 엘리먼트가 하나 있습니다, ㅇㅇㅇ, ㅋㅋ 를 얻는방법?
    • <div ~ >를 $0으로 두고 $0.textContent
      자식element : $0.children
      span, span 만 나옴
      자식 node : $0.childNodes
      텍스트, 여러종류의 elements가 섞여있을 때 사용
      text노드, 자식태그들과 공백들 나옴
      "\n 여기 엘리먼트가 하나있습니다", span, "\n ㅇㅇ", span, "\n ㅋㅋ"

dataset: $0.dataset.~
태그 자체에 데이터를 담고싶을 때
화면에 보이지는 않는다.
숨겨진 데이터를 심고 싶을때 js dataset속성을 통해서 값을 얻어올 수 있다.

<div data-user='steve' data-role='moderator' data-user-id='1'>SteveLee</div>

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

events : 동작 시 action

trigger 종류
click/ mouse events/ keyboard typing/ changing current location/ 기타 등등

  • 클릭이벤트
    <button>에 $0을 두고 console.dir($0);을 통해 button tag와 관련된 속성들을 볼 수 있다.

<onclick><onchange><ondoubleclick><onkeydown><onmousemove><onscroll>등등

사용법: $0.onclick에 함수를 직접 걸어주면된다.
addEventListener

function foo(){
  alert('마우스가 클릭되었습니다')
}
$0.onclick = foo;  //ƒ foo(){alert('마우스가 클릭되었습니다')};

//참고. 위 내용을 아래와 같이 메소드를 이용해 구현할 수도 있다
$0.addEventListener('click', function(){
  alert('마우스가 클릭되었습니다')
});

해당 버튼을 클릭하면 지정한 문자열와 함께 alert창이 뜬다.

사용자의 동작에 반응하는 방법 이외에 사용자가 등록한 내용을 받아와야할 때에는??
ex)사용자가 이름, 댓글내용 입력 후 등록을 눌렀(Click)을 때 ➜ 이 때 동작할 함수 작성
함수에 $0로 할 수 있는 속성이 없다. (언제까지 $0으로만 DOM을 다룰 수가 없다)

🔎 특정 element를 선택하고 가져오는 법

사용자의 이름을 어떻게 변수로 받아올 것인가?
댓글 내용을 어떻게 변수로 받아올 수 있을까?

  • 태그를 이용: getElementsByTagName
  • id를 이용: getElementById
  • class를 이용: getElementsByClassName
  • selector를 이용: querySelector/ querySelectorAll(이 두가지가 위 3개를 대체가능)

사용방법:

document.querySelectorAll('.comment')
//선택된 곳의 comment이름을 가진class를 선택

➜ NodeList라는 유사배열형태로 []에 담겨 나옴
이 유사배열을 변수에 담아서 배열처럼 호출가능

let allComments = document.querySelectorAll('.comment');
allComments[0]

querySelectorAll : 여러개의 tag선택, class를 여러개 선택할 때

📌 id값처럼 하나의 태그를 받아올 때는 querySelector사용하면 된다.
어차피 id는 1개니까 0번째까지 밖에 없으므로 굳이 배열로 받아올 필요가 없다.

  • ex) querySelector('#userName');
    //해당id태그가 있는 태그가 불러와진다

Q. 사용자가 이름과 댓글을 입력했을 때 값을 받아서 값을 담은 값을 콘솔에 출력하려면?

function getInputValue(){
//user name과 comment를 선택
let eleUsername = document.querySelectorAll('#username');
let eleNewComment = document.getElementById('comment');
//username과 comment의 값을 얻어온다
Alert(eleUsername.value);
Alert(eleNewComment.value);
}

getInputValue();  //사용자가 이름과 댓글창에 입력한 값이 실행된다

//버튼을 눌렀을때 위의 동작이 실행되게 하려면?
/* <button>에 id설정을 해준 후에 (다른 button들과 겹칠 수 있으므로)
해당버튼을 <button id='register'>라고 했을때 */
document.querySelector('#register').onclick = getInputValue;

사용자의 입력값을 받아오고 받아온 값으로 이벤트 출력

그 다음
받아온 값이 화면에 설정된 형식에 맞게 출력되어야 한다.

예를 들어, 트윗을 하면 트윗 목록에 사용자명/ 트윗내용/ 날짜시간 등이 출력되어서 목록처럼 쌓여야함 ➜ **DOM을 조작해야 함

DOM 조작

  • method
  • .innerHTML (tag를 만들 수 있다. 쓰기 쉬운 속성 but 느리고 보안위협)
    ➜.innerContent(더 안전, 권장)
<div id="target">변경 전</div>
let target = document.querySelector('#target');
target.innerHTML = `
  <span>변경 후</span>
`;

HTML출력결과

<div id="target"><span>변경 후</span></div>
  • method( .createElement('태그이름'): '태그이름'element 생성)
<div id="target">변경 전</div>
let target = document.querySelector('#target');
let newSpan = document.createElement('SPAN'); //동적으로 엘리먼트 생성
newSpan.innerHTML='변경 후'; //만든span에 내용채워넣기, 단순string이라 textConten로도 넣기가능
target.appendChild(newSpan); //자식으로 넣으려는 method, 만든 span태그를 삽입
//target아래쪽에 newSpan 엘리먼트 추가

/* .appendChild()는
js를 이용해서 만든 element를 화면에 뿌려줄 수 있다(=newSpan을 target에 추가해줄 수 있다)
변경 전(=target) 아래쪽에 <span>가 담긴변수 newSpan 추가 */
<div id="target">
   변경 전
   <span>변경 후</span>
</div>

➕ 이해를 돕기위한 예제
목적 : 새로운 트윗 한개가 등록되면 기존에 올라와있는 트윗목록(<li class="comment">..</li>)에
새로운 트윗 하나가 더 추가되도록 하는 것
1. 먼저 새 엘리먼트 li를 만든다.
2. li에 내용을 추가한다.
3. 삽입하려는 대상(부모)엘리먼트를 선택해서 가져온다.
4. 부모엘리먼트(<div id='view-comments'>..</div>)에 새 엘리먼트 li를 추가한다.

function appendNewComment(){
  let li = document.createElement('LI');
  
  li.innerHTML = '<div class='username'>adela</div> <div class='contents'>새로운 트윗</div>' //HTML tag자체를 넣고싶을때,
  //li.textContent를 사용해도 된다
  let parent= document.querySelector('#view-comments')
  parent.appendChild(li)
}

appendNewComment();

위 과정을 통해서 새로운 li태그들이 실행할 때마다 생겨난다.
이제 생겨난 li태그들에게 기존에 올라와있는 목록들처럼 class지정해주기
1. 위 함수에 li.className = 'comment'추가
2. 사용자 이름과 트윗내용이 달라져도 함수가 작동할 수 있게 parameter로
사용자이름과 내용을 지정하고 채울 내용에도 parameter 적용 (id, content)

function appendNewComment(id, content){
  let li = document.createElement('LI');
  li.className = 'comment'
  li.innerHTML = '<div class='username'> + id + </div> <div class='contents'> + content + </div>' //HTML tag자체를 넣고싶을때,
  //li.textContent를 사용해도 된다
  let parent= document.querySelector('#view-comments')
  parent.appendChild(li)
}

appendNewComment('새 사용자', '새 내용');

target.innerHTML = ""  //공백문자를 넣어놓으면 삭제한다는 뜻
target.remove();  //method로 해당태그 삭제

HTML에서 <script>태그의 위치

script.js 파일을 만들어 console.log('Hello World')를 적어 놓고
index.html이 완성되면 마지막 body태그 끝나기 직전에

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

꼭 body태그가 닫히기 직전에 해줘야 DOM에 접근할 수 있다.
body태그 안의 요소들이 다 그려지기 전인 script태그를 맨위에 넣으면 접근이 안된다.

연결해준 후에 새로고침해보면 해당 파일이 열린 브라우저 콘솔창에 "Hello World"가 출력된다.

vanilla javascript: 어떠한 라이브러리도 쓰지않고 조작하는 javascript를 말한다.

  • 'vanilla javascript dom manipulation cheat sheet'
  • 'cheet sheet'

키워드로 검색해서 필요할 때마다 찾아 쓰면 된다.

참고 element vs node
Element는 Node이다 (Node에 속해있다.)
Text는 Node이나, Element는 아니다. (문자열을 담은 객체)

profile
👩🏼‍💻 SWE (FE)

0개의 댓글