게시글

5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭
강좌14 - JavaScript - 9년 전 등록 / 7년 전 수정

DOM

이번 시간에는 DOM에 대해 알아보겠습니다. 

DOM

DOM이란 Document Object Model입니다. document를 객체로 구현했다고 생각하면 됩니다. F12에서 콘솔 대신에 Elements 탭을 보면 html 구조가 나와있습니다. html은 이미 알고 있다는 가정 하에 진행하겠습니다. html은 정말 쉬우니까요..

html
-head
--title
--meta
--link
-body
--header#header
---nav
---div
--main
--footer
---"hello"
--script

같은 구조로 되었습니다. 즉 계층적 구조로 되어있는데요. header, main, footer, script의 부모는 body이고, head와 body의 부모는 html이라고 할 수 있습니다. head와 body는 형제자매 관계이겠죠. header는 body의 자식이고요. footer의 안에는 태그 대신 "hello"라는 문자가 들어있습니다. 전 시간에 다룬 텍스트 노드죠.

이걸 잘 생각해보면 객체로 표현할 수 있습니다.

{
  document: {
    html: {
      head: {
        title: ...
      },
      body: {
        header: ...
      }
    }
  }
}

이렇게 들어갈 수 있습니다. 위와 같이 만든 게 DOM입니다. 정말 객체 모양으로 표현됐죠? 가장 위는 document고요. 자식으로 갈 때는 html 태그를 건너 뛰고, head와 body로 갑니다. head와 body는 각각 document.head, document.body로 접근할 수 있습니다.

Node와 Element

잠시 Node와 Element에 대해 알아보겠습니다! Node는 태그 노드와 텍스트 노드 전체를 가리키고, Element는 텍스트 노드를 제외하고, 흔히 생각하는 태그(<a>같은)만 가리킵니다. 따라서 태그만 검색하고 싶을 때는 Element가 붙은 메소드를 선택해야합니다. 아래는 자주 쓰이는 DOM의 속성입니다.

속성

태그.nodeType

일단 태그를 선택한 후 nodeType 속성을 검색하면 해당 태그의 종류를 알려주는 숫자가 나옵니다.

  • 1(Node.ELEMENT_NODE) -> Element 
  • 3(Node.TEXT_NODE) -> 텍스트 
  • 8(Node.COMMENT_NODE) -> 주석 
  • 9(Node.DOCUMENT_NODE) -> Document
  • 10(Node.DOCUMENT_TYPE_NODE) -> DOCTYPE 
  • 11(Node.DOCUMENT_FRAGMENT_NODE) -> Document Fragment 

중간에 빈 2, 4, 5, 6은 더 이상 쓰이지 않는 숫자입니다. 7은 거의 안 쓰기 때문에 뺐습니다. 뒤에 Node.[노드 상수] 해도 같은 값이 나옵니다. Node.ELEMENT_NODE == 1입니다.

태그.children, 태그.childNodes

자식으로 갈 때는 children(텍스트 노드 제외)또는 childNodes(텍스트 노드 포함)를 사용합니다.

document.body.children; // [header, main, footer, script]

따라서 main을 선택하고 싶다면 document.body.children[1]을 선택하면 되는 거죠.

DOM의 속성들은 모든 태그에 다 사용할 수 있습니다. 즉 document부터 head, body, script, div, span 등 모든 태그에 다 지원됩니다. document.getElementById('header')로 가리킨 태그도document.getElementById('header').children하면 #header의 자식들이 나옵니다. 

한번에 document.getElementsByTagName('main')하면 편할 것은 왜 굳이 children 이런 것을 쓰냐고요? 한 번에 선택할 때는 getElementsByTagName같은 메소드가 더 편하지만 main의 부모를 찾아라, 또는 main의 자식들을 찾아라 할 때는 이름을 모르기 때문에 children같은 속성을 사용하는 겁니다.

태그.firstChild, 태그.firstElementChild, 태그.lastChild, 태그.lastElementChild

모든 자식을 선택하는 대신, 첫 번째 자식만 선택하고 싶다면 firstChild 속성이 있습니다. 마지막을 선택하고 싶으면 lastChild가 있고요.

document.body.firstChild; // <header>...</header>
document.body.lastchild; // <script>...</script>

firstElementChild, lastElementChild는 같은 역할을 하지만, 텍스트 노드는 무시합니다.

태그.parentNode, 태그.parentElement

부모를 찾을 때는 parentNode 속성을 사용합니다. 

document.body.parentNode; // <html>...</html>

자식은 여러 개일 수 있기 때문에 children이나 childNodes같은 복수형 단어를 썼다면 부모는 항상 한명이기 때문에 단수형 parentNode입니다.

태그.previousSibling, 태그.nextSibling, 태그.previousElementSibling, 태그.nextElementSibling

형제자매 태그를 찾을 때는 previousSibling, nextSibling을 씁니다. sibling이 형제자매라는 뜻이거든요. 각각 바로 전이나 바로 다음 형제자매를 찾아줍니다.

document.getElementsByTagName('main')[0].nextSibling; // <footer></footer>

previousElementSibling, nextElementSibling은 역시 텍스트 노드를 무시합니다.

태그.innerHTML, 태그.outerHTML

선택한 태그의 내용물을 얻어오거나 바꿀 수 있습니다.

var footer = document.getElementsByTagName('footer')[0];
footer.innerHTML; // 'hello'
footer.innerHTML = 'goodbye';

원래의 내용이던 hello를 goodbye로 바꿨습니다. 텍스트 외에도 태그를 집어 넣을수도 있습니다.

footer.innerHTML = '<b>bold</b>';

굵은 글씨의 bold 텍스트가 들어갑니다. outerHTML은 현재태그까지 포함한 문자열을 반환합니다.

footer.outerHTML = '<footer><b>bold</b></footer>';

태그.속성

var tag = document.getElementById('header');
tag.id; // 'header'

태그를 선택하고 그 속성을 조회할 수 있습니다. 바꿀 수도 있고요. id, className(class), name, value, placeholder, checked, disabled, readonly 같은 속성 값을 볼 수 있습니다.

태그.attributes

해당 태그가 가진 모든 속성을 보고싶다면 attributes 속성을 사용하면 됩니다. 

태그.clientHeight, 태그.clientWidth

태그의 margin, border, scrollbar을 제외한 높이와 너비를 반환합니다.

태그.offsetHeight, 태그.offsetWidth

태그의 margin만 제외한 높이와 너비를 반환합니다.

태그.scrollHeight, 태그.scrollWidth

스크롤 가능한 범위까지 포함한 태그의 높이와 너비를 반환합니다.

아래는 자주 쓰이는 태그의 메소드들입니다. DOM을 조작하려면 꼭 알아두어야 합니다.

메소드

태그.appendChild

이전 시간에 createElement() 함수로 만들었던 태그를 넣을 때 이 메소드가 필요합니다. 마지막 순서의 자식 태그로 추가됩니다.

var newElement = document.createElement('div');
document.body.appendChild(newElement);

위의 코드처럼 하면 body의 마지막 자식 태그로 div 태그가 하나 추가됩니다.

태그.removeChild

선택한 자식 태그를 삭제합니다.

document.body.removeChild(document.body.childNodes[document.body.childNodes.length - 1]);

body의 마지막 자식 태그를 삭제하는 코드입니다. document.body.childNodes[document.body.childNodes.length - 1]가 마지막 자식 태그를 선택하는 코드고요.

태그.insertBefore

appendChild가 자식 태그로 집어넣는 거라면 insertBefore 메소드는 자신의 형제 태그로 집어넣습니다. 자신 이전에요.

var newElement = document.createElement('div');
document.body.insertBefore(newElement, document.getElementById('header'));

위의 코드는 부모.insertBefore(넣을 태그, 기준 태그)입니다. 위의 코드는 body의 자식으로, header 이전에 새로 만든 div태그를 넣으라는 뜻이죠.

태그.cloneNode

자신을 복사합니다. 복사한 것을 저장해서 appendChild나 insertBefore로 집어넣으면 되겠죠?

var clone = document.getElementsByTagName('nav')[0].cloneNode();

다음 시간에는 window 객체의 속성인 DateRegExp 객체에 대해 알아보겠습니다!

조회수:
0
목록
투표로 게시글에 관해 피드백을 해주시면 게시글 수정 시 반영됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright 2016- . 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.
5만명이 선택한 평균 별점 4.9의 제로초 프로그래밍 강좌! 로드맵만 따라오면 됩니다! 클릭

댓글

12개의 댓글이 있습니다.
5년 전
궁금한게 있습니다. console창에 document를 치게 되면 html 이 전부 나오게 되는데 블로그 첫번째에서 언급한것에 따르면 {
document: {
html: {
head: {
title: ...
},
body: {
header: ...
}
}
}
}
이런식으로 된다고 하셨는데 왜 객체형태가 아닌 html 형태로 나오게 되나요?
5년 전
html 객체 형태로 나오는 것입니다. 다만 document.html.head.title 이런식으로 바로 속성으로 접근할 수는 없고 document.children[0].children[0].children[0]으로 간접적으로 접근해야하므로 html 형태로 보면 도움이 됩니다.
5년 전
원래 객체형태로 출력되고 있는 것인데 편의를 위해 html형태로 브라우저에서 출력해준다는 말씀이신건가요?
5년 전
네네 맞습니다.
6년 전
태그.nodeType 이 부분을 어디에 사용하나요 ? 콘솔로 따라는 해봤지만 이게 어디에 쓰는 건지 잘 모르겠어요. 예를 들면 어떤 때에 이것을 활용할 수 있나요?
6년 전
태그 종류에 따라 다른 처리를 해야할 때 씁니다. 예를 들어 텍스트는 무시하거나 할 때 쓸 수 있습니다.
6년 전
Node.[노드 상수] \u003c- 준수한준수님 의견처럼 저도 이부분이 어떤의미인지 잘 이해가 안가는데.. 어떤의미인지 질문드려도 될까요?
6년 전
ELEMENT_NODE 이런 게 노드 상수입니다.
6년 전
var newElement = document.createElement('div');
document.body.appendChild(newElement);
여기서 body만 되나요?? body 대신 main이나 footer를 넣어도 되나요? main이나 footer를 넣어도 안 되던데... 어떻게 넣어야 하나용??? ㅠㅠ

그리고 위와 같이 만든게 DOM이라고 하셨는데 저 객체 형태로 된 것을 script에 쓰면 되는 건가요???
6년 전
document.querySelector('main').appendChild 이런 식으로 하시면 됩니다. script 태그 안에서 접근하시면 되고요.
6년 전
아핳! 감사합니당!
7년 전
마지막 clonenode부분 설명이 스니펫 안에 들어가있네요.^^
7년 전
잘 배우고 있습니다.!! 질문이 하나 있는데 getElementsByTagName을 이용해서 태그를 지정할 시 반환되는 값이 태그형태가 아니라 배열 형태라서 innerHTML같은 속성값을 찍어도 undefined로 뜨네요.. 예제대로 실행이 되지 않는데, 혹시 제가 이해를 잘 못하고 있는건지, 오류가 있는건지 궁금합니다!!
한가지 더 궁금한 점은 'firstElementChild, lastElementChild는 같은 역할을 하지만, 텍스트는 무시합니다.' 이 설명에서 텍스트가 정확하게 무엇을 뜻하는지 기초가 부족해서 이해하기가 어렵습니다. 혹시 한번 더 설명해 주실 수 있을까요?^^ 감사합니다.

7년 전
아아 getElementsByTagName으로 가져온 태그들은 배열 형태라서 뒤에 [0]같은 것을 붙이고 속성을 사용하셔야 합니다. 수정하겠습니다.
firstElementChild 부분에서 텍스트는 html 텍스트를 의미합니다. 그냥 글자들이요. 제 화면에 보이는 Copyright나 ZeroCho나 다 하나의 텍스트 노드입니다. firstElementChild는 그러한 텍스트 노드들은 무시한다는 뜻입니다.
7년 전
아! 이해했습니다. 감사합니다!!^^
8년 전
좋은 블로그 운영이 너무나 감사드립니다!
너무 잘보고있습니다.!!!

Node와 element차이가 아직 익숙하지가 않네요 ㅠㅠ
혹시 조금더 추가 설명 부탁드려도 될까요??

크롬개발자에 적어봐도 똑같이 텍스트랑 태그랑 같이나와서요 ㅠㅠ

감사합니다!
8년 전
Element는 그냥 태그라고 생각하시면 됩니다. 태그니까 안에 텍스트가 있을 수도 있고, 다른 태그가 들어있을 수도 있죠. 반면 Node는 Element에 텍스트, 주석, Doctype, document, documentFragment까지 합친 겁니다.
8년 전
innerHTML 에 넣는 값으로 DB에서 호출한 데이터와 for 문을 통한 데이터를 함수코드로 만든 함수도 가능할까요?

달력을 스크립트로 만들되, 날짜별로 데이터를 개별적으로 관리자에서 입력할 수 있는 기능을 포함시켜서 만들려고 하는데 php 만으로 만든 달력은 뭔가 코딩면이나 사용면에서 효율성이 떨어지는 듯한 느낌이 들어서 스크립트로 만들어서 삽입하는 방식으로 만들어보려고 합니다
8년 전
제가 옛날에 달력 만든게 있는데 제 github에서 zplanner 검색하세요
8년 전
감사합니다 다만 다운을 받아서 보니 지금 제 autoSet 서버틀에 어떤식으로 파일 셋팅을 해야할 지 몰라서 public 폴더내 파일들만 복사해서 오토셋 기본폴더인 pulic_html 에 넣고 index.html 확장자를 index.php ( 현재 index 파일이 .php 만 인식이 됩니다 ) 로 바꿔서 들어가봤는데 최상단 붉은 줄 하나만 노출되고 그 외엔 나오는 것이 없어서 확인은 못해보고 있습니다
8년 전
아 php로 만든 게 아니라서 php로는 안 돌아갑니다. 달력 구현 부분만 보세요.
8년 전
아 그렇군요 감사합니다 달력부분만 확인해보겠습니다
8년 전
제로초님 덕분에 쉽게 배우고 있어서 너무 감사합니다.
내용 중에 Node.[노드 상수] 는
Node.[1] 이런식으로 사용한다는 말씀이신가요? 제가 말귀가 좀 어두운 것 같습니다ㅠ
8년 전
아뇨 Node.ELEMENT_NODE 이렇게요
8년 전
진짜 잘봤어요 새로운거 또 배워갑니다.
8년 전
지금껏 봐온 DOM 개념 중에서 제일 이해가 잘되네요~ 윗분과 마찬가지로 추가설명이 더있으면 개념책으로 내도 손색없을것같아요~
8년 전
감사합니다. 현재 시험 기간이라 업데이트를 못하고 있습니다. 다음 달이 되어야 보충할 수 있을 거 같습니다.
8년 전
좋은 블로그운영에 감사합니다. 위에 noeType 부분 추가설명을 붙여주셨으면 합니다. 저것만봐선 nodeType이 무엇인지 알수가 없습니다
8년 전
지속적인 피드백 감사합니다. 지금 아예 window, document, DOM은 새로 쓸 예정입니다. 더 자세하고 이해하기 쉽게 쓰도록 하겠습니다!