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 문법
레실이
레실이
  • 레실이
    레실이의 티스토리
    레실이
  • 전체
    오늘
    어제
    • 분류 전체보기 (91)
      • SE Bootcamp 내용 정리 (63)
      • 알고리즘 연습 (7)
      • Project 주저리 (4)
      • 기술 면접 source (3)
      • 개발 일상 (12)
      • 생성 AI 활용 (1)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

    fastapi
    문자열
    CSS
    JS
    ORM
    useState
    PickAndDrink
    node
    mongoDB
    JavaScript
    IT
    Python
    node.js
    MVC
    CSR
    데이터베이스
    객체
    CORS
    Ajax
    ubuntu
    비동기
    자료구조
    useRef
    DOM
    state
    알고리즘
    인증/보안
    promise
    react
    Linux
  • 최근 댓글

  • 최근 글

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

티스토리툴바