S1U11 정리

이유정·2022년 9월 14일
0

코드스테이츠 TIL

목록 보기
15/62
post-thumbnail

DOM

이론:
DOM = Document Object Model
HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 Model
자바스크립트로, HTML의 아주 작은 부분까지 접근할 수 있는 구조

활용:
DOM을 이용하면 HTML로 구성된 웹 페이지를 동적으로 움직이게 만들 수 있다.

참고)
HTML은 프로그래밍을 위해서 만들어진 언어가 아니기 때문에 이전에 배웠던 조건문이나 반복문을 사용할 수 없고, 정보를 저장하기에도 적합한 언어가 아니다. 그래서 JavaScript라는 프로그래밍 언어와 DOM을 활용하여 HTML에 접근하고 조작한다.

학습 목표

DOM을 JavaScript로 조작하여 HTML Element를 추가할 수 있다. (CREATE)
DOM을 JavaScript로 조작하여 HTML Element를 조회할 수 있다. (READ)
DOM을 JavaScript로 조작하여 HTML Element를 변경할 수 있다. (UPDATE)
DOM을 JavaScript로 조작하여 HTML Element를 삭제할 수 있다. (DELETE)
생성한 HTML Element를 부모 엘리먼트의 자식 엘리먼트로 포함할 수 있다. (APPEND)

innerHTML, innerText, textContent, value의 차이

https://ninetynine-2026.tistory.com/509

심화 학습 목표
DOM과 JavaScript의 차이에 대해 이해할 수 있다.
createDocumentFragment를 활용하여, 더 효율적으로 DOM을 제어할 수 있다.
HTML5 template tag 사용법을 이해할 수 있다.
element와 node의 차이를 이해할 수 있다.
children과 childNodes의 차이를 이해할 수 있다.
remove와 removeChild의 차이를 이해할 수 있다.
같은 엘리먼트를 appendChild 하면, 기존 엘리먼트를 복사할까?
offsetTop 등을 이용하여 좌표 정보를 조회할 수 있다.
offsetWidth 등을 이용하여 크기 정보를 조회할 수 있다.

create

자바스크립트에서 어떤 작업의 결과를 담으려면 어떻게 해야 할까?
-변수를 선언하고 어떤 작업의 결과를 변수에 할당합니다.

tweetDiv 라는 요소는 현재 공중부양 중, 공중에 떠있는 엘리먼트를 확인하기 위해서는 APPEND 해야 합니다. APPEND 를 이용해 실제 웹 페이지 상에도 보이는 것을 확인할 수 있습니다. 이어지는 콘텐츠 APPEND에서, tweetDiv 를 트리 구조에 연결합니다.

append


const tweetDiv = document.createElement('div') //create
document.body.append(tweetDiv) // append

내용은 어떻게 넣을까?
-다음 콘텐츠인 UPDATE에서 좀 더 자세히 설명합니다.
이번 콘텐츠에서는 textContent 라는 메서드를 활용하면 문자열을 입력할 수 있습니다.

다른 트윗처럼 이쁘게 container 안에 넣을 순 없나요?
-생성한 tweetDiv 를 container 에 넣기 위해서는, container 를 먼저 찾아야 합니다. 어떻게 container 를 찾을 수 있을까요? 위에서 언급했던 DOM 트리를 순회해서 찾을 수 있습니다. 그러나 보다 더 편리한 방법이 있으니 검색해 보시기 바랍니다.

read

자바스크립트에서 원시 자료형인 변수의 값을 조회하기 위해서는, 변수의 이름으로 직접 조회할 수 있습니다. 참조 자료형인 배열은 index를, 객체는 key를 이용해 값을 조회할 수 있습니다.
그러나 DOM은 조금 특별한 방법을 사용해야 합니다. DOM으로 HTML 엘리먼트의 정보를 조회하기 위해서는 querySelector의 첫 번째 인자로 셀렉터(selector)를 전달하여 확인할 수 있습니다. 셀렉터로는 HTML 요소("div"), id("#tweetList"), class(.tweet) 세 가지가 가장 많이 사용됩니다.

참고로 querySelector는 셀렉터를 조회한다는 의미를 가지고 있습니다. query의 의미가 "질문하다"라는 것을 알고 있다면 역할을 쉽게 유추하실 수 있습니다. 이 query라는 단어는 개발자 간에 "ㅇㅇㅇ를 조회한다"라는 의미를 "쿼리를 날리다"라는 jargon(특정 영역에서만 사용되는 단어)로 굳어졌기 때문에 알고 있어야 합니다.

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

HTML 문서에는 클래스 이름이 tweet 인 요소가 여러 개 있는 데, 변수 oneTweet 에 할당된 요소는 단 하나입니다. 여러 개의 요소를 한 번에 가져오기 위해서는, querySelectorAll 을 사용합니다. 이렇게 조회한 HTML 요소들은 배열처럼 for문을 사용하실 수 있습니다. 주의하세요! 앞서 조회한 HTML 요소들은 배열이 아닙니다! 이런 '배열 아닌 배열'을 유사 배열, 배열형 객체 등 다양한 이름으로 부릅니다. 정식 명칭은 Array-like Object 입니다. Array-like Object 같이 개념을 설명하는 용어는 영어로도 명확하게 기억해두는 게 좋습니다.

새롭게 추가된 tweetDiv 는 별도의 class 가 지정되어 있지 않아, CSS를 이용한 스타일링이 적용되지 않습니다. 이어지는 콘텐츠에서는, 새롭게 생성한 tweetDiv 에 class 를 붙여 스타일링을 적용합니다.

update

const oneDiv = document.createElement('div');
oneDiv.textContent = 'dev';
oneDiv.classList.add('tweet')
const container = document.querySelector('#container')
container.append(oneDiv)

class와 id 말고는 다른 attribute를 추가할 수는 없나요?
-MDN에서 setAttribute 라는 메서드를 검색해 보세요.

delete

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

여러 개의 자식 요소를 지우려면, 어떻게 해야 할까요? innerHTML 을 이용하면, 아주 간단하게 모든 자식 요소를 지울 수 있습니다. 컨테이너의 모든 자식 요소를 지우려면, 다음과 같이 입력합니다.

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

innerHTML 을 이용하는 방법은 분명 간편하고 편리한 방식이지만, innerHTML은 보안에서 몇 가지 문제를 가지고 있습니다. 이 방법을 대신할 다른 메서드를 사용합니다. removeChild 는 자식 요소를 지정해서 삭제하는 메서드입니다. 모든 자식 요소를 삭제하기 위해, 반복문(while, for, etc.)을 활용할 수 있습니다. 다음의 코드는 자식 요소가 남아있지 않을 때까지, 첫 번째 자식 요소를 삭제하는 코드입니다.

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);
}

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

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

틀린문제

다음 HTML 문서에서 body 요소의 자식 요소(element)는 총 몇 개?


<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>

body 요소의 자식 요소는 3개. id가 nav, news-contents, footer 인 3가지
그림으로 표현하면, 쉽게 이해할 수 있습니다. 그러나 컴퓨터에게는 이 사실을 어떻게 전달? 자바스크립트에서 DOM은 document 객체에 구현되어 있습니다. 브라우저에서 작동되는 자바스크립트 코드에서는, 어디에서나 document 객체를 조회할 수 있습니다.

DOM 구조 조회/ 객체 속성확인

DOM 구조를 조회할 때에는 console.dir 이 유용합니다. console.dir 은 console.log 와 달리 DOM을 객체의 모습으로 출력합니다.
console.dir 을 이용해 document.body를 조회해 보니, 너무나 많은 속성이 나타납니다. 앞서 학습한 내용을 상기해보면, HTML 엘리먼트에 지정할 수 있었던 다양한 속성이 이미 객체 내에 존재한다고 생각하면 됩니다.

DOM 구조도를 살펴보면 회사의 조직도와 유사한 모습을 발견할 수 있습니다. body가 가장 상위에 있고, 아래에 여러 구성요소가 부모-자식 관계를 가지고 있습니다.

이런 자료 구조를 컴퓨터 공학에서는 트리 구조라고 합니다. 트리 구조의 가장 큰 특징은 부모가 자식을 여러 개 가지고, 부모가 하나인 구조가 반복되는 점입니다. 즉, 부모가 가진 하나 또는 여러 개의 자식 엘리먼트를 조회하는 코드를 작성한다면, 여러 번 반복해서 실행하는 코드가 필요합니다.

DOM CRUDA 코드 모아두기

쭉 읽으면 좋을 것:)

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



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



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

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

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

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



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

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

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

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

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

이벤트 객체

웹 사이트를 서핑하다 보면, 이미지나 카드를 클릭하거나 드래그하는 일이 있습니다. 이렇게 클릭이나 드래그하는 일을 이벤트라고 합니다. 이번 챕터는 기본적인 이벤트를 알고, 이벤트 핸들러를 구현합니다. 구현한 이벤트 핸들러를 적절한 엘리먼트에 적용하여, 사용자가 엘리먼트에 특정 이벤트를 발생시켰을 때 이벤트 핸들러가 동작하도록 합니다.

학습 목표
기초적인 event를 알고, event handler를 element에 적용할 수 있다.
onclick 에 직접 할당하는 것과 addEventListener의 차이를 이해한다.
eventHandler 함수를 만들고, eventHandler의 첫 번째 인자를 사용할 수 있다.

두 버튼의 이벤트 핸들러는 동일한 함수를 사용

두 버튼의 이벤트 핸들러가 동일한 함수에 의해 동작한다는 점을 주목하세요. 어떤 메뉴가 추가되더라도, 하나의 함수를 추가하면 됩니다. 이렇게 함수를 작성하면 함수를 여러 번 재사용할 수 있습니다.

let menus = document.querySelectorAll("button"); //모든 버튼을 가져옵니다.

let btnAmericano = menus[0];
let btnCaffelatte = menus[1];

btnAmericano.onclick = handleClick;
btnCaffelatte.onclick = handleClick; // for 문으로도 충분히 구현할 수 있는 내용입니다.

function handleClick() {
  // 아래의 빈칸(____)을 채우세요.
  let currentMenu = ____; // TODO
  console.log(currentMenu + "를 클릭하셨습니다.");
}

위의 코드에서 현재 메뉴의 이름을 가져오는 방법은 뭘까?

사용자가 버튼을 클릭하면, 그 버튼의 textContent(또는 innerHTML)을 이용해 메뉴의 이름을 가져올 수 있습니다. 사용자가 누른 버튼에 따라 출력되는 이름이 달라지므로, 클릭된 이벤트 객체에서 메뉴의 이름을 가져옵니다. 다시 말해, 이벤트 객체는 사용자 입력(onclick, onkeyup, onscroll 등)을 트리거로 발생한 이벤트 정보를 담은 객체입니다.

event 출력
[object PointerEvent]를 클릭하셨습니다

event.target 출력
[object HTMLButtonElement]를 클릭하셨습니다

event.target.textContent 출력
아메리카노를 클릭하셨습니다

profile
팀에 기여하고, 개발자 생태계에 기여하는 엔지니어로

0개의 댓글