DOM 이란?

참고서적: DOM - 잡았다, 요 돔!, DOM 을 깨우치다

DOM 을 보니 좀더 깊이 공부해야할것으로 느껴졌다. 아마 앞의 진도에서는 자바스크립트를 배우며 DOM 역시 같이 사용할 것이다. 더 깊숙히 공부하기 위해 해당 내용을 정리하며, 공부하도록 하자.
본 내용은 공부할 목적으로 적은 내용이므로, 틀린 내용이 포함될 수 있다.

DOM 은 HTML 문서를 자바스크립트로 사용할 수 있도록 객체화시킨후, 구조화 시킨 것이다.
그래서 Documnet Object Model 이라고 부른다.

이러한 DOM은 HTML 이 어떠한 과정으로 렌더링이 이루어지는지 아는 것이 중요하다.

웹 브라우저는 자신만의 엔진 (Chrome 같은 경우 V8 Engine) 으로, 작성된 HTML, CSS, Javascript 문서를 읽어 화면에 출력한다.

이때 HTML, CSS 를 사용하여 문서를 분석하는데, 이러한 분석을 Pasring 이라한다.
과정은 대략 이러하다.

아래의 단계는 내가 이해하고 있는 단계이다.
내부 로직을 분석해서 알고 있는것이 아니며 추상적으로 이해하고 있기에 틀릴 수 있는 내용이 포함될수 있는점 참고 바란다.


  1. HTML 문서를 위에서 아래로 쭉 읽는다.
  2. 이때 Engine 은 HTML 을 읽어 DOM Tree 를 만든다.

    DOM Tree 란 HTML 을 parsing 하여 HTML tag 상의 연관관계를 Tree 구조로 해석하는 방식을 말한다.
    자세한것은 JAVASCRIPT.INFO 의 DOM 트리 에서 자세히 설명되어 있다.

  3. Engine 은 link 된 css를 만나면, css 를 읽어 CSS Rules 를 만든다.

    CSS Rules 는 HTML 의 특정한 element 를 어떻게 렌더링 할지 알려주는 CSS 문장이라고 보면 된다.

  4. 이렇게 읽은 DOM Tree 와 CSS Rules 를 Attachment 하는 작업이 이루어진다.

    Parsing 된 Tree 는 내부적으로 attach method 를 포함하고 있다.
    이렇게 포함된 attach method 를 Attachment 단계에서 호출하여 DOM Tree 의 정보를 담은 객체로 만든다.

  5. 이렇게 만들어진 객체의 정보를 이용하여 Render Tree를 만든다.

    Render Tree 는 앞서서 이야기한 CSS Rules 와 DOM Tree 의 각 정보를 병합하여 하나의 객체를 만들어 Tree 형식으로 구조화시킨것을 말한다.

  6. 이제 만들어진 Render Tree 의 정보를 이용하여 Layout 하는 과정을 가진다.
    여기의 Layout 과정은 해당 HTML 요소를 배치시키는 과정이라 생각하면 된다.

    보통 문서가 만들어진 이후, Javascript 를 이용하여 Layout 이 변경된다면 이 단계까지 실행된다. 이렇게 Layout 이 변경되는 작업이 이루어질때 보통 reFlow 되었다 이야기 한다.

  7. Layout 과정이 끝나면 Painting 작업이 시작된다.
    Painting 작업은 CSS 의 스타일을 입히는 작업이라고 생각하면된다.

    문서가 만들어진 이후, 스타일이 변경된다면 Painting 작업단계까지 실행된다. 이렇게 Painting 작업이 변경될때 보통 rePaint 되었다 이야기 한다.

  8. 대망의 Display 단계가 시작된다. 간단하게 위 단계가 다 실행되고 화면에 출력하는 것이다.

이렇게 화면이 출력되는 각 단계가 존재한다.

여기서 DOM 은 이러한 객체정보를 가진 Element 를 생성, 수정, 삭제, 읽기(CRUD)를 할 수 있도록 Javascript 객체로 만들어진 것이라고 생각한다.

즉 HTML 을 조작할 수 있도록 만들어진 API 이다.

NODE

Node 는 DOM 에서 사용하는 용어로, 객체화 시킨 요소를 뜻한다.

만약 다음의 HTML 이 있다고 생각하자

<html lang="en">
<head>
    <title>text</title>
</head>
<body>
    
</body>
</html>

이때 아래처럼 Node 가 만들어진다.

[ document ]
   |
[ html ]
  |
---------------
|             |
[ head ]    [ body ]
|           
---         
|           
[ title ]
|
text

이러한 Tree 구조에서 만들어진 이후, 각 구조의 요소를 Node 라고 생각하면된다.
마치 가계관계도 같이 생겼는데 이러한 관계도를 Tree 구조라 한다.

이때 각 Node 를 표현하는 용어가 몇가지 있다.

  1. Leaf Node

    자식이 없는 Node 종단점

  2. Branch Node

    중간 노드

  3. Root Node

    모든 노드들의 부모노드 시작점

이러한 용어는 원할한 소통을 위해 알아두는것이 좋을 듯 싶다.
그렇다면 Node 의 종류를 알아보자

여기서 말하는 nodeType 은 각 type 을 나타내는 숫자값이라고 생각하면 된다.

숫자값은 워낙에 추상적이라, Node 객체에 내장되어 있는 해당 Node 타입값을 가진 프로퍼티도 같이 제공한다.

  1. Document Node

    nodeType: 9
    Node.DOCUMENT_NODE

    Document Node 는 HTML 의 최상위 문서이다. 이는 위에 말한 Root Node 라고 생각하면 된다. 문서에 대한 전역적 접근이 필요할때 사용가능하다.

  2. Attribute Node

    nodeType: 2
    Node.ATTRIBUTE_NODE
    DOM Level 4 에서는 deprecated 되었다 한다.

    HTML 속성을 나타내는 Node 이다.

  3. Text Node

    nodeType: 3
    Node.TEXT_NODE

    HTML의 모든 문자 및 공백을 말한다.

  4. Comment Node

    nodeType: 8
    Node.COMMENT_NODE

    문서상의 주석을 나타내는 Node 이다.

  5. Element Node

    nodeType: 1
    Node.ELEMENT_NODE

    HTML의 각 요소를 말한다고 보면 된다. div, span, input, etc... 같은 모든 요소를 뜻한다.


위의 노드타입은 노드 식별을 쉽게 알아보기 위해 숫자값으로 제공하는 방식이다.
만약 HTML 상에 testElem 이라는 id 를 가진 div element 가 있다고 가정한다

let elem = document.getElementById("testElem");
console.log(elem.nodeType === 1); // true

if (elem.nodeType === 1) { // true
	console.log("엘리먼트이에요"); // 출력
}

이렇게 숫자값으로 출력도 가능한데, 외우기 어렵다면 다음처럼 사용해도 된다.

const elem = document.getElementById("testElem");
console.log(elem.nodeType === Node.ELEMENT_NODE); // true

if (elem.nodeType === Node.ELEMENT_NODE) { // true
	console.log("엘리먼트이에요"); // 출력
}

BOM 은 뭐야?

BOM 은 DOM 과는 다르게 Browser Object Model 을 뜻한다.
이는 브라우저 환경을 객체로 제공하여 변경 가능하도록 만들어진 객체 모델이라고 생각하면 된다.

Element 를 가져와봐요.


querySelectorAll 과 querySelector


DOM 구조에 접근하기 위해서는 Root Node 에 접근하여 Node 를 가져와야 한다.

여기서 list3 을 가진 li를 가져와 보자!!

document.querySelectorAll() 을 말그대로 지정자를 query 하는 메소드이다.
여기에 All 이 붙었으니 해당 메소드를 사용하면, 해당 태그를 전부 가져온다.

해당 태그만 가져오면 되지 태그를 전부 가져오는가?

해당 태그를 가져오기 위해서는 식별할수 있는 식별자가 있어야 한다.
ex) class, id 같은
하지만 식별자가 없을때는 관련된 태그를 전부다 가져와야 한다.
(태그는 배열형식(NodeList)으로 저장된다. 이는 NodeList 에 대해 알아야 한다. NodeList 은 밑에 바로 설명한다.)
가져온 태그들중 원하는 태그를 가져오는 방식을 사용해 본다.
다음을 보자.

NodeList

여기서 중요한 점은 NodeList 는 배열이 아니라는점이다.
객체로 이루어져 있으며 마치 배열처럼 동작하는 ArrayLikeObject 이다.
다음을 보자.

let elems = document.querySelectorAll("li"); // html 상의 모든 li 를 가져온다.
// 이때 elems 는 배열같이 생긴 객체로 되어 있다.
{
	'0': li,
    '1': li,
    '2': li,
    '3': li,
    'length': 4
}

마치 객체로 이루어진 배열 같다.
이러한 객체를 ArrayLikeObject 라 부른다.
여기서 중요한 것은 NodeList 는 배열이 아니지만, 배열처럼 동작한다는것이다.
실제 배열이 아니기에 filter, map, reduce 같은 배열의 method 는 사용할 수 없다.
하지만 편의상 forEach 는 제공하는듯 하다.

IE 에서는 forEach 미지원

NodeList 는 마치 배열처럼 생긴 객체로 이해하자.

이용하기도 편하다 문자열 값으로 CSS 선택자방식을 사용하여 해당 태그 지정이 가능하다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
    <div class="list">
        <ul>
            <li>list1</li>
            <li>list2</li>
            <li>list3</li>
            <li>list4</li>
        </ul>
    </div>
  <script src="./script/index.js"></script>
    
</body>
</html>
// script/index.js
const elems = document.querySelectorAll(".list li");
console.log(elems);// // NodeList[li, li, li, li]
const list3 = elems[2];
console.log(list3); // <li>list3</li>

만약 단일 태그을 가져오고 싶다면 document.querySelector() 를 사용하여 태그를 가져온다. 이 querySelector는 태그 한개만을 가져온다는는 것을 명심하자.

만약, querySelector 를 사용하였는데, 태그가 1개 보다 더 많으면, 해당 태그 목록중 가장 상위의 태그 한개를 반환한다.

querySelector는 보통 식별가능한 식별자가 있을때 많이 사용한다.
아래의 예제는 class active 식별자를 통해서 해당 요소를 가져와 본다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
    <div class="list">
        <ul>
            <li>list1</li>
            <li class="active">list2</li>
            <li>list3</li>
            <li>list4</li>
        </ul>
    </div>
  <script src="./script/index.js"></script>
    
</body>
</html>
// script/index.js
const elem = document.querySelector(".active");
console.log(elem); // li.active

이는 css 선택자 문법을 사용해서 쉽게 해당 요소를 가져올수 있지만, 각 선택자에 따른 다른 메서드들 역시 존재한다.

document.getElementById


document.getElementByIddocument상의 ID selector 를 사용하여 해당 Element를 가져온다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="active">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.getElementById("wrapper");
console.log(elem); // div#wrapper

이는 document 상에 유일한 식별자인 ID 를 사용하므로, getElements 가 아닌 getElement 로 쓴다는것을 명확히 알아두는 것이 좋다.
처음 사용할때 자주 실수하는 부분이다.

document.getElementsByTagName


document.getElementsByTagNamedocument 상의 tag 이름을 식별한다. tag 는 한개가 아닌 여러개일 가능성이 많으므로, 해당 메소드는 항상 유사객체(ArrayLike) 형식으로 반환한다.

중요한것은 querySelectorAll 과는 다르게 NodeList 가 아닌 HTMLCollection 객체를 반환한다.

실상, NodeListHTMLCollection 은 서로 다르면서 비슷한 면이 많다.
이에 대해서는 추후 시간이 되면 다른 파트에서 설명한다.

HTMLCollection실시간 변경 으로 인해 예상치 못한 결과가 발생할 수 있다. 그리므로 꼭 Array 로 변환하여 사용하자.

Array.fromspread opreator 을 사용하여 Array 로 만들어 사용하길 권장한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="active">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elems = document.getElementsByTag("li");
console.log(elems); // HTMLCollection[li, li, li, li.active]

// if 배열로 만든다면 다음과 같다.
const ElemstoArr1 = [...elems]; // or
const ElemstoArr2 = Array.from(elems);  

사용시 단수가 아닌 복수이므로 getElementsBy 로 해야 한다.

document.getElementsByClassName


document.getElementsByClassName 는 말그대로 class 식별자를 사용하여 값을 가진다.
알다시피, classid 와 달리 복수지정이 가능하다. 그러므로 getElementsBy 로 시작한다.

document.getElementsByClassName 역시 HTMLCollection 을 반환한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li class="even">list2</li>
                <li>list3</li>
                <li class="even">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elems = document.getElementsByClassName("even");
console.log(elems); // HTMLCollection[li.even, li.even]

Node 를 탐색해 보아요


만약 Node 만 선택했다면 무쓸모일것이다.
매번 Node를 선택해서 사용하는것은 불편하다.
쓸모있게 만들려면 해당 선택한 Node 를 기점으로 다른 노드를 찾을 수 있어야 한다.
DOM 은 이러한 Navigation 능력도 있다.

document 내의 노드를 훨씬 빠르게 찾을 수 있어서 자바스크립트 최적화에 도움을 줍니다.
DOM - 잡았다, 요 돔!

요소를 탐색해보자.

parentNode


Element.parentNode는 해당 Node 의 부모노드를 찾는다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li class="even">list2</li>
                <li>list3</li>
                <li class="even">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".even");
// .even 을 가진 li중 가장 첫번째 li 를 가져온다
console.log(elem.parentNode); // ul

firstChild


Element.firstChildNode 의 자식중 첫번째 Node를 가져온다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li class="firstChild">list1</li>
                <li>list2</li>
                <li>list3</li>
                <li>list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul"); // ul
console.log(elem.firstChild); //#text

이거 상황이 이상하다.
.list ul 의 자식이면 li.firstChild 가 나와야 하는데 #text 가 나왔다!!

DOM 은 실제 HTML Documnent 상의 공백 텍스트 역시 하나의 Node 로 인식한다.
Node.TEXT_NODEText Node 이다.

공백역시 Text Node 로 인식한다.
이는 띄어쓰기 및 줄바꿈도 포함된다.
위의 상황은 다음과 같다

<!DOCTYPE html>
<html lang="ko"><!-- 공백 텍스트 -->
<head><!-- 공백 텍스트 -->
    <title>Document</title><!-- 공백 텍스트 -->
</head><!-- 공백 텍스트 -->
<body><!-- 공백 텍스트 -->
      <div id="wrapper"><!-- 공백 텍스트 -->
        <div class="list"><!-- 공백 텍스트 -->
            <ul><!-- 공백 텍스트 -->
                <li class="firstChild">list1</li><!-- 공백 텍스트 -->
                <li>list2</li><!-- 공백 텍스트 -->
                <li>list3</li><!-- 공백 텍스트 -->
                <li>list4</li><!-- 공백 텍스트 -->
            </ul><!-- 공백 텍스트 -->
        </div><!-- 공백 텍스트 -->
    </div><!-- 공백 텍스트 -->
  <script src="./script/index.js"></script><!-- 공백 텍스트 -->
</body><!-- 공백 텍스트 -->
</html><!-- 공백 텍스트 -->

ul 부분만 보자면 다음과 같다.

<ul><!-- 공백 텍스트 -->
     <li class="firstChild">list1</li><!-- 공백 텍스트 -->
     <li>list2</li><!-- 공백 텍스트 -->
     <li>list3</li><!-- 공백 텍스트 -->
     <li>list4</li><!-- 공백 텍스트 -->
</ul><!-- 공백 텍스트 -->

여기서 ulfirstChild 는 즉 ul 옆의 공백 택스트 이다.
이러한 텍스트 노드를 chrome devTool 에서는 #text 로 나온다.

그럼 li.firstChild 를 선택하려면, 두번째 자식을 선택해야 한다.
이때 nextSibilng 을 사용한다.

nextSibling


nextSibling 은 선택한 Node 의 다음 Node를 선택한다.

앞의 firstChild 에서 #text(공백 텍스트) 가 나왔다.
원하는 Elementul 다음의 첫번째 li 이다. firstChild 에서 이어서 다음 요소를 탐색해 본다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li class="firstChild">list1</li>
                <li>list2</li>
                <li>list3</li>
                <li>list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.firstChild.nextSibling); // li.firstChild

이번에는 원하는 li.firstChild 가 나온것을 알 수 있다.

lastChild


firstChild 가 있다면 lastChild 도 있을 것이다.
lastChild 는 마지막 Node를 선택한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="lastChild">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.lastChild); // #text

역시 이번에도 #text(공백 문자) 가 나왔다.
이는 앞에서 설명한 대로 Text Node역시 하나의 Node 로 인식하기에 생겨난 현상이다.
앞에서는 nextSibling 을 썼지만, 이번에는 Next 가 아닌 Previous 이다.

previousSibling


previsousSibling 은 해당 Node 의 앞 Node를 선택한다.
위의 내용에서 previousSibling 을 사용해본다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="lastchild">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.lastChild.previousSibling); // <li>list4</li>

정상적으로 <li>list4</li> 가 나오는것을 확인할 수 있다.

다른 Node 속성은 없을까?


일반적으로 위의 명령어들 firstChild, lastChild, nextSibling, previousSibling 들은 전부 method 가 아닌property 임을 명심하자.

위의 속성들은 전부 Node 객체의 property 이다.
Node 객체의 property 는 다음의 테이블과 같다.

namedescription
childNodes자식 노드를 전부 반환한다.
반환요소는 NodeList 이다.
firstChild자식 노드중 첫번째 자식 노드를 반환한다.
lastChild자식 노드중 마지막 자식 노드를 반환한다.
nextSibling선택된 노드에서 다음 노드를 선택한다.
previousSibling선택된 노드에서 이전 노드를 선택한다.
nodeName선택된 노드의 노드 이름을 반환한다.
nodeValue선택된 노드타입이 Node.TEXT_NODE, Node.COMMNET_NODE 일때만 반환한다.
그 이외의 노드타입은 전부 null 값을 반환한다.
nodeType선택된 노드의 노드 타입을 반환한다
parentNode선택된 노드의 부모 노드를 반환한다.

위의 테이블중 다른것은 쉽게 이해가 가는데 nodeValue 부분이 걸린다.
nodeValue 를 좀더 살펴보자.

다음은 앞전의 previousSibling 의 내용을 그대로 가져왔다.
선택된 li.lastChildnodeValue 프로퍼티를 가져와 본다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="lastchild">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.lastChild.previousSibling.nodeValue); // null

null 이 나온다.
위의 테이블에서 nodeValue 의 내용은 다음과 같다

선택된 노드타입이 Node.TEXT_NODE, Node.COMMNET_NODE 일때만 반환한다.
그 이외의 노드타입은 전부 null 값을 반환한다.

위 말은 선택된 노드의 타입이 TEXT_NODECOMMENT_NODE 이어야 한다.
하지만 위의 elem.lastChild.previousSibling 은 노드 타입이 Node.ELEMENT_NODE 이다.

노드 타입을 확인하기 위해 nodeType 속성을 사용해 본다.

nodeType 은 선택된 노드의 노드 타입을 반환한다

다음 script 로 확인해보자.

// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.lastChild.previousSibling.nodeType === Node.ELEMENT_NODE); // true

값은 true 가 나온다.
elem.lastChild.previousSibling 의 노드 타입은 Node.ELEMENT_NODE 로 확인되었다.

그렇다면 li.lastChild 안의 list4 텍스트를 선택하여 nodeValue 속성을 사용하면 값을 반환하지 않을까?

const elem = document.querySelector(".list ul");
console.log(elem.lastChild.previousSibling.firstChild.nodeValue); // list4

이번에는 제대로 값이 반환되는것을 확인 할 수 있다.
nodeValue 는 문자관련 노드에서만 값을 반환하는것을 알게 되었다.

지금까지 Node 관련 속성에 대해서 알아보았다.
사실 Node 로 탐색하는것은 매우 불편한 일이다.
앞에서 보았듯이 empty text도 하나의 Node 로 취급하기 때문이다.
그래서 Node 가 아닌 HTMLElement 내부에 다른 property 들이 존재한다.
HTMLElement 메서드들은 정말 HTMLElement 만 탐색 가능하기에 훨씬 편하게 사용 가능하다.

HTML*Element 를 사용하여 탐색해 보아요.


HTML*Element 는 무엇인가?

HTML 문서 내의 각 element 들은 고유한 성질을 가지며, 각자 element 를 DOM 트리 내의 노드 개체로 인스턴스화하는 고유한 javascript 생성자를 가진다. 예를 들어, <a>HTMLAnchorElement 생성자를 통해 DOM 노드로 만들어진다.

출처: DOM 을 깨우치다

HTMLElement 는 각 객체로 인스턴스화 시키는 생성자가 있다고 말하고 있다. 이러한 생성자를 통해 내부 속성 및 메서드가 만들어진다. 다음은 이러한 생성자를 확인할 수 있는 링크이다.
해당 링크에서 Interface 를 보면 각 HTML*Element 의 생성자를 알 수 있다.

여기서 HTML*Element* 은 해당 Element의 이름이다.

참조링크: HTML*Element 전체목록

나중에 Typescript 공부할 때, DOM Type 에 대한 이해에 유용할 듯 싶다.

Node는 객체이며, Node 를 조작하기 위해 여러가지 Sub Object 를 가진다.
ElementNodeSub Object 이다.
또한 HTMLElementElementSub Object이다.
Nodedocument 역시 Sub Object 중 하나이다.
HTML*Element 를 다루기 위해, NodeSub Object 중 하나인 Element 객체의 속성을 사용하여 내용을 탐색해 본다.

document 객체와 Element 의 중요한 차이점이 존재한다. documentHTML documentRoot NodeHTMLdocument를 직접 참조하여 속성을 사용하지만,
Element 는 선택한 HTMLElement에서 HTML*Element를 참조하여 속성을 사용한다.
즉, 모든 HTML*ElementHTMLElement의 자식이며, Element 의 자손이다.
이제부터 사용하는 속성들은 이러한 Element의 속성을 사용한다.

깊게 들어가면 어렵다ㅠㅠ, 굳이 이해하지 않아도 속성은 구현되어 있으니 그냥 사용하면 된다.

firstElementChild


Element.firstElementChildElement 의 자식중 첫번째 Element를 가져온다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li class="firstChild">list1</li>
                <li>list2</li>
                <li>list3</li>
                <li>list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul"); // ul
console.log(elem.firstElementChild); // li.firstChild

앞에서의 TEXT_NODE 가 아닌 Element를 가져온다.
원하는 Element 를 쉽게 가져올 수 있어서 더 유용하게 사용가능하겠다.

lastElementChild


lastElementChild 는 마지막 Element를 반환한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li>list1</li>
                <li>list2</li>
                <li>list3</li>
                <li class="lastChild">list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.lastElementChild); // li.lastChild

nextElementChild 와 presviousElementChild


nextElementChild 는 선택한 Element 의 다음 Element를 선택한다.

<!DOCTYPE html>
<html lang="ko">
<head>
    <title>Document</title>
</head>
<body>
      <div id="wrapper">
        <div class="list">
            <ul>
                <li class="previousChild">list1</li>
                <li class="nextChild">list2</li>
                <li>list3</li>
                <li>list4</li>
            </ul>
        </div>
    </div>
  <script src="./script/index.js"></script>
</body>
</html>
// script/index.js
const elem = document.querySelector(".list ul");
console.log(elem.firstChild.nextElementChild); // li.nextElemetChild

원하는 li.nextElementChild 가 나온것을 알 수 있다.
이번에는 해당 요소의 이전 lili.previouseChild를 탐색해보자.

// script/index.js
const elem = document.querySelector(".list ul");
const nextChild = elem.firstChild.nextElementChild; // li.nextChild
console.log(nextChild.prevousElementChild); // li.previousChild

Node 탐색과는 다르게 쉽게 원하는 Element를 탐색한다.
다음은 Element 에서 제공하는 탐색 관련 속성들의 테이블이다.

namedescription
childern자식 요소를 전부 반환한다.
반환요소는 HTMLCollection 이다.
firstElementChild자식 요소중 첫번째 자식 요소를 반환한다.
lastElementChild자식 요소중 마지막 자식 요소를 반환한다.
nextElementChild선택된 요소에서 다음 요소를 선택한다.
previousElementChild선택된 요소에서 이전 요소를 선택한다.

이상으로 DOM 탐색 및 선택에 대해 알아보았다.
다음은 생성 및 추가에 대해서 알아본다.

profile
익숙해지면 다 할수 있어!!

0개의 댓글