Loko
로코
Loko
전체 방문자
오늘
어제
  • 분류 전체보기
    • Essay
      • 월기장
      • Code States
      • Conference 후기
    • Book
      • Hard Skill
      • Soft Skill
      • Novel
      • Science
      • Economy
      • Self Help
    • Troubleshooting
      • in Works
      • in Projects
      • in Lectures
    • JVM
      • Java
      • Kotlin
      • Spring
      • JPA
    • JavaScript
      • Vanilla
      • React
      • Redux
      • Next
    • Algorithm
      • 기본적으로 알아야 할 것들
      • Java class library package
      • Sorting Algorithm
      • 꼭 기억해둘 유명 Algorithm
      • 유형별 풀이 template
    • Infrastructure
    • Web
      • 기초 공부
      • 서적 공부
      • Security
      • AWS

블로그 메뉴

  • 홈
  • GitHub
  • 기술 블로그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Loko

로코

JavaScript/Vanilla

DOM (Document Object Model)

2021. 7. 24. 17:15

DOM (Document Object Model) 이해하기

DOM은 프로그래머 관점에서 바라본 HTML이다.
HTML 요소를 Object(JavaScript Object)처럼 조작(Manipulation)할 수 있는 모델이다.
JavaScript를 사용할 수 있으면 DOM으로 HTML을 조작할 수 있다 는 말이다.
쉽게 얘기하자면, JavaScript를 이용해서 엘리먼트의 속성값을 얻어내거나 변경하는 방법이라고 이해하면 된다.
하지만 DOM을 JavaScript라고 이해하면 안된다. 단지 JavaScript를 통해 접근하는 것 뿐이다.

이 DOM을 만들기 위해 뛰어난 웹 개발자들이 모여서 HTML을 철저히 분석했다.
분석한 내용으로 HTML의 아주 작은 부분까지 접근할 수 있는 구조(Model / Structure)를 만들어냈다.
이렇게 만들어진 구조를 이용해서 HTML로 구성 페이지를 동적으로 움직이게 만들 수 있게 되었다.
이러한 DOM을 활용하면 웹 페이지를 조금 더 다이나믹하게 만들 수 있다.

 

HTML에서 JavaScript가 적용되는 방식

HTML에 JavaScript를 적용하기 위해서는 script 태그를 이용한다.
아래의 경우 파일과 같은 디렉토리에 있는 js 파일을 불러온다.

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

웹 브라우저가 작성된 코드를 해석하는 과정에서 위와 같은 script 요소를 만나면 웹 브라우저는 HTML 해석을 잠시 멈춘다.
그 다음 script 요소를 먼저 실행하게 된다.
여기서 반드시 명심해야 할 점은 script 요소는 등장과 함께 실행된다는 사실 이다.

script 태그를 추가하는 두 가지 대표적인 방법이 있다.
하나는 head 태그에 추가하는 방법이고, 다른 하나는 body 태그가 끝나기 전에 추가하는 방법이다.
그 중, body 태그가 끝나기 전에 추가하는 방법을 활용해야 모든 기능이 정상 작동한다.

 

자식 엘리먼트 찾기

브라우저에서 작동되는 JavaScript 코드에서는 어디에서나 documnet 객체를 조회할 수 있다.

console dir

DOM 구조를 조회할 때에는 console.dir이 유용하다.
왜냐하면 cosole.log와 달리 console.dir은 DOM을 객체의 모습으로 출력하기 때문이다.
console.dir(document.body)와 같이 사용할 수 있다.
여기서 document는 DOM을 대표하는 객체이다.

 

부모 엘리먼트 찾기

부모 엘리먼트를 조회하려면 자식 엘리먼트의 첫 번째 엘리먼트를 조회하면 된다.

console.dir(documnet.body.children[1]);

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

let newContents = document.body.children[1];

 

console.dir 객체의 속성들

console.dir을 통해서 객체 형식으로 출력하면 객체의 속성들이 상당히 많은 것을 확인할 수 있다.
아래의 표를 통해서 특별히 기억해두면 좋을 속성들을 정리하였다.

속성 이름 속성
tagName 태그 이름
id id
classList class 목록
className class 문자열
attributes 속성 객체
style 스타일 객체
innerHTML, innrText, innerContent 엘리먼트에 담긴 내용
value form 입력 값
children 자식 엘리먼트
parentElement 부모 엘리먼트
childNodes 자식 노드
dataset data-* 속성에 담긴 값
onclick, onmouseover, onkeyup 등 이벤트
offsetTop, offsetLeft,scrollTop, scrollLeft,clientTop, clientLeft 좌표 정보 (기준점)
offsetWidth, offsetHeight,scrollWidth, scrollHeight,clientWidth, clientHeight 크기 정보 (기준점)
  • attributes는 id와 class 등 태그 안의 속성들을 배열 형태로 보여준다.
  • innerHTML은 태그를 포함해서 보여주고, textContent는 태그 안의 문자열만 보여주며, 이 둘은 안의 내용을 바꿀 수 있다.
  • value를 통해 입력값을 받는 양식에서 편하게 입력값을 확인할 수 있다.
  • children은 자식의 태그들만을 볼 수 있지만, childNodes는 안에 포함된 태그 이외의 요소들도 같이 보여준다.
  • dataset은 화면에는 보이지 않는 데이터를 담아두고 싶을 때 사용할 수 있다.
<div data-user="steve" data-role="moderator" data-user-id="1">
    Steve Lee
</div>

 

추가적인 DOM의 개념들

  1. Node는 Element의 상위 개념이다. DOM 관련 객체는 대부분 Node에서 파생되었다고 봐도 과언이 아니다. Node의 기능을 적용(implemets)한 객체는 여러 타입이 있는데, 그 중 가장 많이 사용되는 타입이 Element이다.
  2. DOM은 document 객체를 통해 HTML에 접근하며, BOM(Browser Object Model)는 window 객체를 통해 브라우저에 접근한다.
  3. 다른 언어도 DOM을 가지고 있지만 JavaScript의 DOM이 전통적으로 오래 쓰여왔으며 안정적이다.

 

DOM으로 HTML 조작하기

DOM으로 엘리먼트 선택하기

  • 태그를 이용 : getElementsByTagName
  • id를 이용 : getElementById
  • class를 이용 : getElementsByClassName
  • selector를 이용 : querySelector / querySelectorAll

=> selector를 이용해서 찾는 방법을 많이 사용하게 될 것이지만, 다른 사람의 코드를 이해하기 위해서 다른 방법들도 알아두어야 한다.

※ querySelectorAll과 같은 방법으로 조회한 엘리먼트들은 배열과 유사하지만 배열이 아니다. 정식 명칭은 Array-like Object이다.

 

DOM으로 생성하기

<div id="target">변경 전</div>
let target = document.querySelector("#target");
let newSpan = document.createElement("SPAN");
newSpan.className = "test";
// newSpan.classList.add("test"); 의 방법도 이용 가능
newSpan.innerHTML = "변경 후";
target.appendChild(newSpan);
<div id="target">
  변경 전
  <span class="test">변경 후</span>
</div>

 

DOM으로 덮어쓰기

innerHTML

<div id="target">변경 전</div>
let target = document.querySelector("#target");
target.innerHTML = `
  <span>변경 후</span>
`;
<div id="target">
  <span>변경 후</span>
</div>

가장 쓰기 쉬운 속성이지만 느리고 보안 위험이 있다. textContent가 더 안전하다.

 

DOM으로 삭제하기

innerHTML

let target = document.querySelector("#target");
target.innerHTML = "";

 

메소드를 이용한 엘리먼트 삭제

let target = document.querySelector("#target");
target.remove();

 

동일한 클래스 이름이면 삭제

const tweets = document.querySelectorAll(".tweet");
tweets.forEach(function (tweet) {
  tweet.remove();
});

 

추가적인 메소드

setAttribute()

let aElement = document.createElement("a");
aElement.setAttibute("id", "javascipt");
aElement.textContent = "awesome";

위와 같이 setAttribute 메소드를 사용하면 aElement의 id 속성에 'javascript'라는 값을 넣어줄 수 있다.

 

removeChild()

document.querySelector("#world").remove();
document.querySelector("#world").remove(aElement);

위의 2개의 코드는 괄호 안의 값과 상관 없이 world라는 id를 가진 엘리먼트 전부를 지우게 된다.

document.querySelector("#world").removeChild(aElement);

이렇게 하면 world의 나머지 값들은 보존하고 자식 중에서 aElement만 지울 수 있게 된다.

 

버튼 클릭

function displayAlert() {
  alert("코드스테이츠에 오신 것을 환영합니다");
}
document.querySelector("#apply").onclick = displayAlert;
document.querySelector("#apply").addEventListener("click", function () {
  alert("코드스테이츠에 오신 것을 환영합니다");
});

이벤트 발생 시 작동하는 함수를 할당하는 방법은 두 가지가 있다.
DOM 객체에 onclick을 직접 지정하는 방법과 addEventListener라는 메소드를 사용해서 할당하는 방법이다.
주의해야 할 점은 함수를 할당할 시에 함수의 실행값을 할당하면 안되고 함수 그 자체를 할당해야 한다는 점이다.

function displayAlert() {
  alert("코드스테이츠에 오신 것을 환영합니다");
}
document.querySelector("#apply").onclick = displayAlert();

이렇게 사용하면 정상적으로 작동하지 않는다.

 

DOM의 이벤트 객체

DOM을 통한 이벤트 호출 방법

직접 호출

let testInput = document.querySelector("#test-input");

testButton.onkeyup = validFunction;

function validFunction() {
  console.log("키를 눌렀다 떼었습니다.");
}

 

이벤트 리스너를 통한 호출

let testInput = document.querySelector("#test-input");

testInput.addEventListener("keyup", function () {
  console.log("키를 눌렀다 떼었습니다.");
});

//or

testInput.addEventListener("keyup", () => {
  console.log("키를 눌렀다 떼었습니다.");
});

//or

testInput.addEventListener("keyup", sampleFunc);

function sampleFunc() {
  console.log("키를 눌렀다 떼었습니다.");
}

 

DOM의 이벤트들

keyup

  • 키를 놓을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onkeyup

keydown

  • 키를 눌렀을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onkeydown

change

  • 값이 변경된 후 포커스도 벗어났을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onchange

focus

  • 포커스가 해당 엘리먼트에 갔을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onfocus

blur

  • 포커스가 해당 엘리먼트에서 벗어났을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onblur

submit

  • form 태그의 action이 발생하기 직전에 이벤트 발생
  • 이벤트 핸들러 속성 : onsubmit

mouseover

  • 해당 엘리먼트에 마우스가 올라왔을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onmouseover

mouseout

  • 해당 엘리먼트에서 마우스가 나갔을 때 이벤트 발생
  • 이벤트 핸들러 속성 : onmouseout

onload

  • 브라우저가 페이지 load를 끝냈을 때 이벤트 발생

event.preventDefault

  • 이벤트를 취소할 경우, 이벤트의 전파를 막지 않고 이벤트를 취소
function checkName(evt) {
  var charCode = evt.charCode;

  if (charCode != 0) {
    if (charCode < 97 || charCode > 122) {
      evt.preventDefault();
      alert(
        "소문자만 입력할 수 있습니다." + "\n" + "charCode: " + charCode + "\n"
      );
    }
  }
}

 

DOM 추가 정리 (append / prepend)

  • append는 이미 있는 자식 요소들의 뒤쪽에 추가
  • prepend는 이미 있는 자식 요소들의 앞쪽에 추가
  • 부모.append(자식)
  • 자식.appendTo(부모)

★ 면접을 위해 - DOM이란?

=> HTML 문서를 객체의 형식으로 가공하기 위해 만든 멘탈 모델 / HTML의 트리 구조와 JavaScript 객체의 트리구조가 멘탈 모델이 같게 함

childNodes

자식들 중 엘리먼트와 엘리먼트가 아닌 텍스트 및 빈 공간들까지 같이 반환해준다.
children 메소드를 사용하면 자식들 중 엘리먼트만 반환된다.

document.documentElement.scrollTop

현재 스크롤의 위치를 알 수 있다.

document.addEventListener("scroll", handleScroll);

위와 같이 이벤트 핸들러와 사용할 수도 있다.
잘 만든 웹 사이트들을 구경해보면 스크롤을 내릴 때마다 화려한 화면 전환 효과를 볼 수 있는데, 바로 이 이벤트를 활용한 것이다.

addEventListener의 특징 한 가지

이벤트가 누적된다.
button.onclick = func; 같은 식으로 클릭 함수를 지정할 경우에는 한 가지 이벤트만 할당된다.
removeEventListener를 통해 겹친 이벤트 중 특정 이벤트를 지울 수도 있다.

event.preventDefault()

버튼 클릭과 같은 이벤트의 경우에 어떤 동작도 하지 않았으면서 웹 페이지를 새로 갱신하는 것을 방지한다.
이렇게 되면 기존에 하려던 것을 못하고 화면이 넘어가 버릴 수 있다.

저작자표시 (새창열림)

'JavaScript > Vanilla' 카테고리의 다른 글

class, 그리고 JS의 객체 지향  (0) 2021.07.27
고차함수  (0) 2021.07.27
객체의 얕은 복사와 깊은 복사  (0) 2021.07.24
Hoisting  (0) 2021.07.24
Spread와 Rest 문법  (0) 2021.07.24
    'JavaScript/Vanilla' 카테고리의 다른 글
    • class, 그리고 JS의 객체 지향
    • 고차함수
    • 객체의 얕은 복사와 깊은 복사
    • Hoisting
    Loko
    Loko
    개발하면서 발전하고 싶은 소망이 담긴 블로그입니다.

    티스토리툴바