js/brower - DOM -1

2021. 9. 10. 17:24·SE Bootcamp 내용 정리


js/browser – DOM(Document Object Model)

DOM은 프로그래머 관점에서 바라 본 HTML

DOM 이해하기

DOM은 Document Object Model의 약자로, HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model입니다. 즉, 여러분이 자바스크립트를 사용할 수 있으면, DOM으로 HTML을 조작할 수 있습니다.

학습 목표

* DOM의 개념
* DOM의 구조와 HTML과 비교
* HTML에서 JavaScript 파일을 불러올 때의 주의점
- `<script>` 태그가 적용되는 위치에 따라서 실행 결과가 달라짐
* DOM과 JavaScript의 차이

HTML에 JavaScript 적용하기

<script> 태그를 사용

 

<script src="myScriptFile.js"></script>    // html 파일과 같은 디렉토리에 있는 ~파일 불러옴

 
→ 웹 브라우저는 코드를 해석하는 과정에서 <script>요소를 만나면 html 해석을 일시 정지하고 <script>요소를 먼저 실행한다. 그 후에 다시 html 해석
→ <script> 요소는 등장과 함께 실행된다

<script> 태그를 추가하는 2가지 방식

1.<head>안쪽에 삽입하는 경우

<head> 태그에 추가하는 경우로 html 문서의 head 영역에 script 요소가 포함됨

2.<body>태그가 끝나기 전에 삽입하는 경우

가 끝나기 전에 추가하는 방법으로 html 문서의 body 영역의 끝에 script 요소가 포함됨

두 방식의 공통점과 차이점?

두 방식 모두 myScriptFile.js 내의 첫 번째 console.log를 성공적으로 출력하지만,
두 번째 console.log의 경우 제대로 출력하지 못하는 예시
 

console.log('welcome JavaScript');    // 'welcome JavaScript' 두 방식 모두 정상 출력

let msgElement = document.querySelector('#msg');
console.log(msgElement);    //    head방식: null 출력     body방식: <div id="msg">Hello JavaScript!</div> 출력 (boby 내에 msg라는 id가 존재하고 그 내용이 Hello JavaScript!)

왜 그럴까?
→ 1번 방식에서 null 이 출력 되는 것은 head 방식이므로 html을 다 해석하기도 전에 script 태그를 만나므로 2번째 console.log에서 참조할 id를 알 수 없다(아직 html을 읽어들이지도 못했으니깐)
 
→ 즉, html 엘리먼트를 이용하려면 2번 방법(body방식)을 사용해야 할 것이다

JavaScript에서의 html 표현

<html>
  <body>
    <div id="nav">
      <div class="logo"></div>
      <div class="menu-wrapper">
        <div class="menu"></div>
        <div class="menu"></div>
        <div class="menu"></div>
        <div class="profile-photo"></div>
      </div>
    </div>
    <div id="news-contents">
      <div class="news-content-wrapper">
        <div class="news-picture"></div>
        <div class="news-title"></div>
        <div class="news-description"></div>
      </div>
    </div>
    <div id="footer"></div>
  </body>
</html>

위의 예시를 통한 구조 분석하기

Q1. body 엘리먼트의 자식 엘리먼트는 총 몇개?
 
Q2. id의 이름이 news-contents인 div 엘리먼트의 부모 엘리먼트는?
 
Q3. id의 이름이 nav인 div엘리먼트를 포함해서 모든 자식 엘리먼트의 class 이름을 console.log를 사용하여 확인하는 방법을 수도코드로 생각해보자
 

// 만약 id값이 nav라면 nav를 출력  
// 그 안에서 또 만약, class의 값이 logo거나 menu-wrapper라면 그것을 출력?  

 
→ 이런 구조 분석하는 게 html 자체만 보고 쉽지 않다
→ 그래서 자바스크립트라는 프로그래밍 언어와 DOM을 활용하여 HTML에 접근하고 조작

Q1 - 자식 엘리먼트 찾기

A) 3개: nav, news-contents, footer
 
자바스크립트에서 DOM은 document 객체에 구현되어 있다. 브라우저에서 작동되는 자바스크립트 코드에서는, 어디에서나 document 객체를 조회할 수 있음

→ console.dir이 유용 : DOM을 객체의 모습으로 출력
 

console.dir(document.body);

Q2 - 부모 엘리먼트 찾기

A) body 엘리먼트
 

//document.body.children 으로 body의 자식 엘리먼트 찾고 여기서 1번 key인  news-contents를 변수로 저장
let newsContents = document.body.children[1];

newsContents.parentElement;    //    <body>...</body>    출력

 
사용법: node.parentElement

Q3 – DOM 순회하기

html 구조는 트리 구조. 트리 구조에서 부모가 가진 하나 또는 여러 개의 자식 엘리먼트를 조회하는 코드를 작성한다면, 여러 번 반복해서 실행하는 코드가 필요
 

function consoleLogAllElement(element){
// nav의 class 이름을 console.log 합니다.
// nav의 자식 엘리먼트가 있는지 검색합니다. (logo, menu-wrapper)
  //logo의 class 이름을 console.log 합니다.
  //logo의 자식 엘리먼트가 있는지 검색합니다. (없음)
  //menu-wrapper의 class 이름을 console.log 합니다.
  //menu-wrapper의 자식 엘리먼트가 있는지 검색합니다. (menu, menu, menu, profile-photo)
    //첫 번째 menu의 class 이름을 console.log 합니다.
    //첫 번째 menu의 자식 엘리먼트가 있는지 검색합니다. (없음)
    //두 번째 menu의 class 이름을 console.log 합니다.
    //두 번째 menu의 자식 엘리먼트가 있는지 검색합니다. (없음)
    //세 번째 menu의 class 이름을 console.log 합니다.
    //세 번째 menu의 자식 엘리먼트가 있는지 검색합니다. (없음)
    //profile-photo의 class 이름을 console.log 합니다.
    //profile-photo의 자식 엘리먼트가 있는지 검색합니다 (없음)
 //자식 엘리먼트를 모두 탐색했음으로, 함수 실행이 종료됩니다.
//자식 엘리먼트를 모두 탐색했음으로, 함수 실행이 종료됩니다.
}

 


DOM으로 HTML 조작하기

CRUD(Create, Read, Update and Delete)를 통한 연습
→ document 객체를 통해서 HTML 엘리먼트를 만들고(CREATE), 조회하고(READ), 갱신하고(UPDATE), 삭제하는(DELETE) 하는 방법 연습
 
DOM에는 HTML에 적용(APPEND)하는 메소드가 따로 있으니 주의

학습 목표

* DOM을 JavaScript로 조작하여 html Element를 추가, 삭제, 변경하기
- CREATE: createElement
- READ: querySelector, querySelectorAll
- UPDATE: textContent, id, classList, setAttribute
- DELETE: remove, removeChild, innerHTML=””, textContent=””
- APPEND: appendChild
- innerHTML과 textContent의 차이

심화 목표

- createDocumentFragment를 활용한 DOM 제어
- HTML5 template tag 사용법
- element와 node의 차이
- children과 childNodes의 차이
- remove와 removeChild의 차이
- 같은 엘리먼트를 appendChild하면 기존 엘리먼트를 복사할까?
- offsetTop: 좌표 정보 조회
- offsetWidth: 크기 정보 조회

CREATE – createElement

새로운 element를 생성
 

document.createElement('div')    // document 바로 하단에 div 엘리먼트 생성

 
자바스크립트에서 어떤 작업의 결과를 담으려면?
→ 변수를 선언하고 어떤 작업의 결과를 변수에 할당
 
여기서는 div element를 변수 tweetDiv 에 할당

 

const tweetDiv = document.createElement('div')

 

→ 화면 상에는 아무 변화가 없다 현재 tweetDiv 요소는 공중부양 상태
아무 node와도 연결이 되어 있지 않은 하나의 node 상태다
 
→ 이렇게 공중부양된 엘리먼트 확인하기 위해서는 APPEND 해야 보인다.

APPEND – append, appendChild

tweetDiv(공중부양된 엘리먼트)를 트리 구조와 연결하는 작업
→ append 라는 메소드를 사용해서, 변수 tweetDiv 를 body 안에 넣기

 

document.body.append(tweetDiv)        // 변수 tweetDiv에 담긴 새로운 div 엘리먼트를 body 엘리먼트에 append(적용)

READ – querySelector, querySelectorAll

DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(Selector)를 전달하여 확인
→ 셀렉터로는 HTML 태그("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용

querySelector

querySelector 에 '.tweet' 을 첫 번째 인자로 넣으면, 클래스 이름이 tweet 인 HTML 엘리먼트 중 첫 번째 엘리먼트를 조회
 

const oneTweet = document.querySelector('.tweet')

querySelectorAll

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

이렇게 조회한 HTML 엘리먼트들은 배열처럼 for문을 사용하실 수 있습니다. 주의하세요! 앞서 조회한 HTML 엘리먼트들은 배열이 아닙니다! 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체 등 다양한 이름으로 부릅니다. 정식 명칭은 Array-like Object

 

const tweets = document.querySelectorAll('.tweet')    // querySelectorAll로 클래스 이름이 tweet 인 모든 HTML 엘리먼트를 유사 배열로 받아 옴

 

cf.) get으로 시작하는 DOM 조회 메소드: querySelector와 비슷한 역할을 하는 옛날 방식의 메소드
→ 브라우저 호환성(이전 버전 등) 등의 문제로 쓰는 경우도 있다

 

const getOneTweet = document.getElementById('container')    //get 메소드
const queryOneTweet = document.querySelector('#container')
console.log(getOneTweet === queryOneTweet) // true

생각해보기

querySelector에 대한 심화 학습

 

querySelector의 첫번째 인자에 ‘div’를 넣으면 어떻게 될까?    //문서 내 첫번째 div를 출력?
querySelector를 통해서 더 복잡한 작업이 가능?        // #(id) .(class) input 등을 이용하면 되긴 함
QuerySelector의 부모는 꼭 document 객체여야 하나?

UPDATE – textContent, classList.add

기존에 생성한 빈 div 태그를 업데이트하여, 보다 다양한 작업 해보기
→ textContent 를 사용해서, 비어있는 div 엘리먼트에 문자열을 입력

 

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

 
앞서 생성한 div 엘리먼트를 container에 append 했을 때, CSS 스타일링이 적용되지 않았는데 CSS 스타일링이 적용될 수 있도록, div 엘리먼트에 class를 추가

→ classList.add(‘클래스명’)

 

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

 
clss와 id 외에 다른 attribute를 추가하는 것은?

 

Element.setAttribute(name, value);

DELETE – remove, removeChild

삭제하는 방법에도 여러가지가 존재

remove

삭제하려는 엘리먼트의 “위치”를 알고 있는 경우에 사용하는 방법

→ node.remove()

 

const nav = document.querySelector('#nav')
const tweetDiv = document.createElement('div')
nav.append(tweetDiv)
tweetDiv.remove()     // 이렇게 append 했던 엘리먼트를 삭제할 수 있다.

innerHTML

여러 개의 자식 엘리먼트를 지우는 경우 사용
→ innerHTML을 활용
→ 모든 자식 엘리먼트가 지워짐!

 

document.querySelector('#container').innerHTML = '';
//id가 container인 엘리먼트 아래의 모든 엘리먼트를 지웁니다

 
→ 그런데 innerHTML은 보안에서 몇가지 문제를 가지고 있다!
→ 내용이 보호되지 않고 조회해서 다 보이는 듯?(보안상 위험 존재)

 

`<script>` tag를 활용하여 강제로 해커가 원하는 스크립트를 실행시키는 XSS Attack이 대표적

 
→ 다른 메소드를 사용하는 게 좋다; removeChild

removeChild

자식 엘리먼트를 지정해서 삭제하는 메소드
모든 자식 엘리먼트를 삭제하기 위해서 반복문 활용(while, for , …)
 
→ node.removeChild(엘리먼트키워드) // 엘리먼트키워드: node.firstChild, lastfirChild, ...
 

ex) 자식 엘리먼트가 남아있지 않을 때까지, 첫 번째 자식 엘리먼트를 삭제하는 코드

const container = document.querySelector('#container');
while (container.firstChild) {
  container.removeChild(container.firstChild);
}

 
→ 그런데 removeChild와 while을 이용해 자식 요소를 삭제하면 제목에 해당하는 H2”Tweet List” 까지 삭제된다. 이를 방지하기 위한 방법은?

 

case1) 자식 엘리먼트가 1개만 남을 때까지, 마지막 자식 엘리먼트를 제거

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

 

case2) 클래스 이름이 tweet인 엘리먼트만 찾아서 제거

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

심화 학습을 위해 생각해보기

* element와 node의 차이(difference between element and node in javascript dom)
* children과 childNodes의 차이(difference between children and childNodes in javascript dom)
* removeChild와 remove의 차이(difference between removeChild and remove in javascript dom)
* tweets에 forEach는 되는데, reduce는 안되는 이유(why array method is not working on nodelist)
* tweets를 유사 배열에서 배열로 바꾸는 방법 (how to convert nodelist into javascript array)

 


아이디가 "javascript"이고, 내용이 "awesome"인 a 태그를 생성하는 방법

case1) 

let aElement = document.createElement('a')
aElement.setAttribute('id', 'javascript')
aElement.textContent = 'awesome'

aElement    //    <a id=”javascript”>awesome</a>

case2)

let aElement = document.createElement('a')
aElement.id = 'javascript'
aElement.innerHTML = 'awesome'

aElement    //    <a id=”javascript”>awesome</a>

insertBefore(), cloneNode(), appendChild(), prependChild(), insertAfter()

사용법은 mdn 검색…

버튼을 클릭하면 안내창 문구가 나오게 하는 방법?

<body>
   <div>
    <div>hello</div>
    <div id="world">world</div>
    <span id="code">code</span>
    <span>states</span>
    <button id="apply">apply</button>    // 해당 버튼
  </div>
</body>

 

case1) DOM 객체에 onclick을 직접 지정

function displayAlert() {
  alert('안내창입니다’)
}
document.querySelector('#apply').onclick = displayAlert
// 함수를 할당할 때 함수의 실행값(displayAlert() )을 할당하면 안되고
// 함수 그 자체( displayAlert)를 할당해야 한다!


case2)  addEventListener 메소드를 사용해서 할당

document.querySelector('#apply').addEventListener('click', function(){
   alert("안내창입니다")
})

'SE Bootcamp 내용 정리' 카테고리의 다른 글

js/browser - DOM -2  (0) 2021.09.13
js/browser - 유효성 검사 실습  (0) 2021.09.10
얕은 복사, 깊은 복사 내용에 대한 정리?  (0) 2021.09.10
js/node - spread/rest 문법  (0) 2021.09.09
js/node - 자료형, 스코프, 클로저  (0) 2021.09.08
'SE Bootcamp 내용 정리' 카테고리의 다른 글
  • js/browser - DOM -2
  • js/browser - 유효성 검사 실습
  • 얕은 복사, 깊은 복사 내용에 대한 정리?
  • js/node - spread/rest 문법
레실이
레실이
  • 레실이
    레실이의 티스토리
    레실이
  • 전체
    오늘
    어제
    • 분류 전체보기 (81)
      • SE Bootcamp 내용 정리 (63)
      • 알고리즘 연습 (7)
      • Project 주저리 (4)
      • 기술 면접 source (3)
      • 개발 일상 (2)
      • 생성 AI 활용 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    useState
    문자열
    KPT
    알고리즘
    MVC
    useRef
    react 기초
    CSR
    DOM
    PickAndDrink
    CORS
    ORM
    Ajax
    객체
    state
    node
    IT
    Linux
    promise
    cmarket
    linux 기본 명령어
    자료구조
    node.js
    JS
    데이터베이스
    CSS
    중복 순열
    인증/보안
    react
    JavaScript
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
레실이
js/brower - DOM -1
상단으로

티스토리툴바