DOM

이보아·2024년 6월 30일
0

모던_자바스크립트

목록 보기
1/18
post-thumbnail

✅ 노드 삽입

Node.prototype.appendChild 메서드는 인수로 전달받은 노드를 자신을 호출한 노드의 마지막 자식 노드로 Dom에 추가한다.
이때 노드를 추가할 위치를 지정할 수 없고, 언제나 마지막 자신 노드를 추가한다.

  • 마지막 노드로 추가
<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </body>
  <script>
    // 요소 노드 생성
    const $li = document.createElement('li');

    // 텍스트 노드 'Orange'를 <li> 요소에 추가
    $li.appendChild(document.createTextNode('Orange'));

    // 생성된 <li> 요소를 <ul> 요소의 마지막 자식으로 추가
    document.getElementById('fruits').appendChild($li);
  // Apple - Banana - Orange
  </script>
</html>

  • 지정한 위치에 노드 삽입
    Node.prototype.insertBefore(newNode, childNode)메서드는 첫 번째 인수로 전달받은 노드를 두 번째 인수로 전달받은 노드 앞에 삽입한다.
<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');

    //  새로운 <li> 요소 생성
    const $li = document.createElement('li');

    // 텍스트 노드 'Orange'를 <li> 요소에 추가
    $li.appendChild(document.createTextNode('Orange'));

    // 생성된 <li> 요소를 <ul> 요소의 마지막 자식 노드 앞에 삽입
    $fruits.insertBefore($li, $fruits.lastElementChild);
    // Apple - Orange - Banana
  </script>
</html>
  • insertBefore를 사용하여 OrangeBanana 앞에 삽입

  • 두 번째 인수로 null을 전달한 경우
    새 노드는 자동으로 부모 노드의 마지막 자식 노드로 삽입됩니다. appendChild와 같은 동작을 합니다.

<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');

    // 새로운 <li> 요소 생성
    const $li = document.createElement('li');

    // 텍스트 노드 'Orange'를 <li> 요소에 추가
    $li.appendChild(document.createTextNode('Orange'));

    // 생성된 <li> 요소를 <ul> 요소의 마지막 자식으로 삽입 (null을 전달)
    $fruits.insertBefore($li, null);
   // Apple - Banana - Orange 
  </script>
</html>
  • null을 전달하여 Orange를 리스트의 마지막에 추가.

요약

  1. appendchild : Apple - Banana - Orange
  2. insertBefore (마지막 자식 노드 앞) : Apple - Orange - Banana
  3. insertBefore (null) : Apple - Banana - Orange

사용 사례

  • appendchild : 리스트, 댓글 새로운 요소를 리스트 끝에 추가할때 사용
  • insertBefore : 특정 순서에 맞춰 리스트에 새로운 요소를 삽입, 특정 위치에 UI요소를 동적으로 추가할때 사용

✅ 노드 이동

DOM에 이미 존재하는 노드를 appendChild 또는 insertBefore 메서드를 사용하여 DOM에 다시 추가하면

현재 위치에서 노드를 제거하고 새로운 위치에 노드를 추가한다. 즉, 노드가 이동한다.

<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
      <li>Banana</li>
      <li>Orange</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');

    // 이미 존재하는 요소 노드를 취득
    const [$apple, $banana, ] = $fruits.children;

    // 이미 존재하는 $apple 요소 노드를 #fruits 요소 노드의 마지막 노드로 이동
    $fruits.appendChild($apple); // Banana - Orange - Apple

    // 이미 존재하는 $banana 요소 노드를 #fruits 요소의 마지막 자식 노드 앞으로 이동
    $fruits.insertBefore($banana, $fruits.lastElementChild);
    // Orange - Banana - Apple
  </script>
</html>

요약

  1. appendChild를 사용하면 선택한 노드를 마지막 자식으로 이동합니다. ( Banana - Orange - Apple )
  2. insertBefore를 사용하면 선택한 노드를 특정 노드 앞에 이동합니다. ( Orange - Banana - Apple)

✅ 노드 복사

Node.prototype.ChildNode([deep : true | false]) 메서드는 노드의 사본을 생성하여 반환한다.

매게변수 deep에 true를 인수로 전달하면 노드를 깊은 복사하여 모든 자손 노드가 포함된 사본을 생성하고,

false를 인수로 전달하거나 생략하면 얕은 복사하여 노드 자신만의 사본을 생성한다.

이때 텍스트 노드도 자손 노드이므로 텍스트 노드도 복사되지 않는다.

<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');
    const $apple = $fruits.firstElementChild;

    // $apple 요소를 얕은 복사하여 사본을 생성. 텍스트 노드가 없는 사본이 생성된다.
    const $shallowClone = $apple.cloneNode();
    // 사본 요소 노드에 텍스트 추가
    $shallowClone.textContent = 'Banana';
    // 사본 요소 노드를 #fruits 요소 노드의 마지막 노드로 추가
    $fruits.appendChild($shallowClone);

    // #fruits 요소를 깊은 복사하여 모든 자손 노드가 포함된 사본을 생성
    const $deepClone = $fruits.cloneNode(true);
    // 사본 요소 노드를 #fruits 요소 노드의 마지막 노드로 추가
    $fruits.appendChild($deepClone);
  </script>
</html>

  • 얕은 복사 (shallow copy) : cloneNode(false) 또는 cloneNode()를 사용하여 노드를 얕게 복사합니다. 노드 자신만 복사하고 그 자식 노드들은 복사하지 X
<ul id="fruits">
  <li>Apple</li>
  <li>Banana</li>
</ul>

  • 깊은 복사 (deep copy) : cloneNode(true)를 사용하여 노드를 깊게 복사합니다. 깊은 복사는 노드 자신과 모든 자식 노드를 복사합니다.
<ul id="fruits">
  <li>Apple</li>
  <li>Banana</li>
  <ul id="fruits">
    <li>Apple</li>
    <li>Banana</li>
  </ul>
</ul>

요약

  • cloneNode(false), cloneNode() : 얕은 복사(노드 자신만 복사)
  • cloneNode(true): 깊은 복사(모든 자식 노드 복사)

사용 사례

  • 무한으로 재생되는 슬라이드
  • 템플릿 기반 동적 콘텐츠 생성
  • 폼 필드 복제
  • 대화형 목록 생성

✅ 노드 교체

Node.prototype.replaceChild(newChild, oldChild) 메서드는 자신을 호출한 노드의 자식 노드를 다른 노드로 교체한다.

첫 번째 매개변수 newChild에는 교체할 새로운 노드를 인수로 전달하고, 두 번째 매개변수 oldChild에는 이미 존재하는 교체될 노드를 인수로 전달한다.

<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');

    // 기존 노드와 교체할 요소 노드를 생성
    const $newChild = document.createElement('li');
    $newChild.textContent = 'Banana';

    // #fruits 요소 노드의 첫 번째 자식 요소 노드를 $newChild 요소 노드로 교체
    $fruits.replaceChild($newChild, $fruits.firstElementChild);
   // Banana
  </script>
</html>

요약

  • replaceChild(newChild, oldChild): 기존 노드를 새로운 노드로 교체합니다.
  • 첫 번째 인수로 새로운 노드를, 두 번째 인수로 교체될 기존 노드를 전달합니다.

사용 사례

  • 사용자 프로필 업데이트할때
const profileContainer = document.getElementById('profile');
const newProfile = document.createElement('div');
newProfile.textContent = 'New Profile Information';
profileContainer.replaceChild(newProfile, profileContainer.firstElementChild);
  • 상태 변화 시 UI 업데이트

✅ 노드 삭제

Node.prototype.removeChild(child) 메서드는 child 매개변수에 인수로 전달한 노드를 DOM에서 삭제한다.

<!DOCTYPE html>
<html>
  <body>
    <ul id="fruits">
      <li>Apple</li>
      <li>Banana</li>
    </ul>
  </body>
  <script>
    const $fruits = document.getElementById('fruits');

    // #fruits 요소 노드의 마지막 요소를 DOM에서 삭제
    $fruits.removeChild($fruits.lastElementChild);
   // Apple 
  </script>
</html>

사용 사례

  • 목록에서 항목 제거
const list = document.getElementById('task-list');
const task = list.querySelector('.task');
list.removeChild(task);

📌 어트리뷰트

HTML 문서는 여러 요소로 구성됩니다. 각 HTML 요소는 여러 개의 어트리뷰트(속성)를 가질 수 있습니다.

어트리뷰트는 HTML 요소의 동작을 제어하는 추가적인 정보를 제공합니다. HTML 요소의 시작 태그에서

어트리뷰트는 어트리뷰트이름="어트리뷰트값" 형식으로 정의됩니다.

<input type="text" id="name" value="user1">

✅ 어트리뷰트 노드와 attributes 프로퍼티

HTML 문서가 파싱 될때 각 어트리뷰트는 어트리뷰트 노드로 변환된다.
ex(3개의 어트리뷰트 -> 3개의 어트리뷰트 노드 생성) attributes 프로퍼티는

NamedNodeMap 객체에 담겨 요소 노드의 attributes 프로퍼티에 저장되고, 읽기 전용이다.(getter)
값을 접근하려면 요소.attributes.어트리뷰트명.value로 접근한다.

<!DOCTYPE html>
<html>
  <body>
    <input type="text" id="name" value="user1">
    <script>
      // <input> 요소의 attributes 프로퍼티를 가져옵니다.
      const {attributes} = document.getElementById('name');
      console.log(attributes);
      // NamedNodeMap {0: id, 1 : type, 2: value, id: id, type : type, value: value, lengtg:3}


      // 각 어트리뷰트의 값을 출력합니다.
      console.log(attributes.id.value);    // "name"
      console.log(attributes.type.value);  // "text"
      console.log(attributes.value.value); // "user1"
    </script>
  </body>
</html>

image

✅ HTMl 어트리뷰트 조작

attributes 프로퍼티를 통하지 않고 요소 노드에서 메서드로 바로 HTML 어트리뷰트 값 접근 가능

  • Element.prototype.getAttribute(attributeName) : 어트리뷰트 값을 가져옴
  • Element.prototype.setAttribute(attributeName,attributeValue) : 어트리뷰트 값을 설정함
  • Element.prototype.hasAttribute(attributeName) : 어트리뷰트가 존재하는지 확인
  • Element.prototype.removeAttribute(attributeName) : 어트리뷰트를 제거
<!DOCTYPE html>
<html>
  <body>
    <input type="text" id="name" value="user1">
    <script>
      const inputElement = document.getElementById('name');
      
      // getAttribute로 'value' 어트리뷰트 값을 가져옴
      console.log(inputElement.getAttribute('value')); // user1

      // setAttribute로 'value' 어트리뷰트 값을 'changed'로 변경
      inputElement.setAttribute('value', 'changed');
      
      // 변경된 'value' 어트리뷰트 값 확인
      console.log(inputElement.getAttribute('value')); // changed
    </script>
  </body>
</html>

✅ HTML 어트리뷰트 vs DOM 프로퍼티

HTML 어트리뷰트는 HTML 태그에 작성된 속성이며, 요소의 초기 상태를 지정한다. (변화 X)

DOM 프로퍼티는 javaScript 객체의 속성이다. 요소의 최신 상태를 관리한다. 사용자 입력, 스트립트에 의해 변경 될 수 있다.

HTML 어트리뷰트: 밑에 예제에서 <input type="text" id="name" value="user1">에서 value="user1"는 초기값을 설정합니다.
DOM 프로퍼티: 자바스크립트에서 접근할 수 있는 요소의 현재 상태를 나타냅니다. 예를 들어 input.value는 사용자가 입력한 현재 값을 나타냅니다.

<!DOCTYPE html>
<html>
  <body>
    <input type="text" id="name" value="user1">
    <script>
      const input = document.getElementById('name');
      
      // 초기 DOM 프로퍼티 값 출력
      console.log(input.type);  // "text"
      console.log(input.id);    // "name"
      console.log(input.value); // "user1"

      // 사용자가 값을 "user2"로 변경했다고 가정
      input.value = 'user2';

      // DOM 프로퍼티 값 출력
      console.log(input.value); // "user2"

      // HTML 어트리뷰트 값 출력
      console.log(input.getAttribute('value')); // "user1"
    </script>
  </body>
</html>
  • 처음 로드되었을 때 input.value는 "user1"입니다.
  • 사용자가 값을 "user2"로 변경하면, input.value는 "user2"로 업데이트됩니다.
  • 하지만, input.getAttribute('value')는 여전히 초기값인 "user1"을 반환합니다.
  • 따라서, DOM 프로퍼티는 요소의 현재 상태를 반영하고, HTML 어트리뷰트는 요소의 초기 상태를 유지합니다.

id 어트리뷰트와 id 프로퍼티는

  • 항상 동일한 값을 유지한다
  • 하나가 바뀌면 나머지도 변경됨

HTML 어트리뷰트와 DOM 프로퍼티의 대응 관계

  • id: 어트리뷰트 → id 프로퍼티
  • class: 어트리뷰트 → className, classList 프로퍼티
  • for 어트리뷰트 → htmlFor 프로퍼티
  • 어트리뷰트에 대응하는 프로퍼티는 카멜 케이스를 따른다.(htmlFor, className, classList)
<!DOCTYPE html>
<html>
  <body>
    <label for="username">Username:</label>
    <input id="username" type="text" value="JohnDoe">
    <input id="check" type="checkbox" checked>
    <script>
      const usernameInput = document.getElementById('username');
      const checkboxInput = document.getElementById('check');

      // DOM 프로퍼티 출력
      console.log(usernameInput.id); // "username"
      console.log(usernameInput.type); // "text"
      console.log(usernameInput.value); // "JohnDoe"
      console.log(checkboxInput.checked); // true

      // HTML 어트리뷰트 출력
      console.log(usernameInput.getAttribute('id')); // "username"
      console.log(usernameInput.getAttribute('type')); // "text"
      console.log(usernameInput.getAttribute('value')); // "JohnDoe"
      console.log(checkboxInput.getAttribute('checked')); // "checked"
    </script>
  </body>
</html>
  • 이 예제는 label, input[type="text"], input[type="checkbox"] 요소를 사용하여 HTML 어트리뷰트와 DOM 프로퍼티의 대응 관계를 명확하게 보여줍니다.

  • label 요소의 for 어트리뷰트는 htmlFor 프로퍼티에 대응합니다.

  • input[type="text"] 요소의 id, type, value 어트리뷰트는 각각 id, type, value 프로퍼티에 대응합니다.

  • input[type="checkbox"] 요소의 checked 어트리뷰트는 checked 프로퍼티에 대응합니다.

  • 이렇게 다양한 어트리뷰트를 가진 요소들을 사용하여 각 어트리뷰트와 대응하는 DOM 프로퍼티를 확인할 수 있습니다.

✅ data 어트리뷰트와 dataset 프로퍼티

data 어트리뷰트

  • 정의: HTML 요소에 사용자 정의 데이터를 저장할 수 있는 어트리뷰트이다.
  • 형식: data- 접두사 + 사용자 정의 이름 = "값"
  • 예: <li data-user-id="1" data-gender="male">John</li>

dataset 프로퍼티

  • 정의: JavaScript에서 data 어트리뷰트에 접근하기 위한 프로퍼티이다.
  • 반환값: 모든 data 어트리뷰트를 담은 DOMStringMap 객체를 반환한다.
  • 이름 변환: data- 접두사 다음의 이름을 카멜 케이스로 변환한다.
    • 예: data-user-id -> dataset.userId
<!DOCTYPE html>
<html>
  <body>
    <ul>
      <li data-user-id="1" data-gender="male">John</li>
      <li data-user-id="2" data-gender="female">May</li>
    </ul>
    <script>
      const users = [...document.querySelector('ul').children];
      // 성별이 'female'인 사용자 찾기
      const female = users.find(user => user.dataset.gender === 'female');
      console.log(female.textContent); // May
      console.log(female.dataset.userId); // 2
    </script>
  </body>
</html>

📌 스타일

✅ 인라인 스타일 조작

HTML 요소의 인라인 스타일을 JavaScript로 조작할 수 있다.
1. style 프로퍼티 : 인라인 스타일로 접근 변경 가능하며, style 프로퍼티를 참조하면 CSSStyleDeclaration 객체를 반환한다.
2. CSSStyleDeclaration 객체: JavaScript에서는 프로퍼티 이름을 카멜케이스로 사용 (예) backgroundColor)프로퍼티에 값을 할당하면 인라인 스타일로 추가 된다.

<!DOCTYPE html>
<html>
  <body>
    // 인라인 스타일 방식 
    <div style="width: 100px; height: 100px; background-color: red;"></div>
     // CSSStyleDeclaration 객체 방식
    <script>
      const div = document.querySelector('div');
      console.log(div.style); // CSSStyleDeclaration 객체 출력
      div.style.backgroundColor = 'blue'; // 배경색을 파란색으로 변경
      div.style['background-color'] = 'green'; // CSS 표기법으로 배경색을 초록색으로 변경
    </script>
  </body>
</html>

✅ 클래스 조작

HTML 요소에 클래스(class)를 추가하거나 제거하여 스타일을 변경할 수 있다. class 어트리뷰트에 대응하는 DOM 프로퍼티인 className,classList를 통해 적용된다.

className

  • 클래스 이름을 문자열로 가져오거나 설정합니다.
  • 클래스가 여러 개일 때는 공백으로 구분된 문자열이 반환됩니다.
<!DOCTYPE html>
<html>
  <body>
    <!-- 인라인 스타일 적용된 div 요소 -->
    <div style="width: 100px; height: 100px; background-color: red;"></div>
    <script>
      const div = document.querySelector('div');

      // CSSStyleDeclaration 객체 출력
      console.log(div.style); // CSSStyleDeclaration 객체

      // 인라인 스타일 변경 - 배경색을 파란색으로 변경
      div.style.backgroundColor = 'blue';

      // 다른 방식으로 인라인 스타일 변경 - 배경색을 초록색으로 변경
      div.style['backgroundColor'] = 'green'; 
    </script>
  </body>
</html>

classList

  • 클래스 리스트를 DOMTokenList 객체로 반환한다.
  • 여러 가지 메서드를 제공하여 클래스를 조작할 수 있습니다.

DOMTokenList 객체의 메서드

메서드설명예시 (JavaScript)
add(...className)인수로 전달한 문자열을 class 어트리뷰트에 추가element.classList.add('class1', 'class2')
remove(...className)인수로 전달한 클래스를 class 어트리뷰트에서 삭제element.classList.remove('class1', 'class2')
item(index)인덱스에 해당하는 클래스를 반환element.classList.item(0)
contains(className)클래스가 있는지 여부를 반환 (true/false)element.classList.contains('class1')
replace(oldClassName, newClassName)기존 클래스를 새로운 클래스로 교체element.classList.replace('oldClass', 'newClass') 있다.

✅ 요소에 적용되어 있는 CSS 스타일 참조

인라인 스타일

  • style 프로퍼티: HTML 요소에 직접 작성된 인라인 스타일만 반환한다.
  • 예:
    요소의 스타일만 반환한다.
<!DOCTYPE html>
<html>
  <body>
    <div style="color: red;">Hello</div>
    <script>
      const div = document.querySelector('div');
      console.log(div.style.color); // "red"
    </script>
  </body>
</html>

모든 스타일 참조

  • getComputedStyle 메서드: 클래스나 상속을 통해 적용된 모든 스타일을 참조할 수 있습니다.
  • 사용 방법: window.getComputedStyle(element)
<!DOCTYPE html>
<html>
  <head>
    <style>
      .blue {
        color: blue;
      }
    </style>
  </head>
  <body>
    <div class="blue">Hello</div>
    <script>
      const div = document.querySelector('div');
      const styles = window.getComputedStyle(div);
      console.log(styles.color); // "blue"
    </script>
  </body>
</html>

📌 DOM 표준

  • WHATWG: Web Hypertext Application Technology Working Group의 약자로, 구글, 애플, 마이크로소프트, 모질라가 참여한다.
  • W3C와 WHATWG: 두 단체가 HTML과 DOM 표준을 만들기 위해 협력해왔다.
  • 2018년 이후부터 WHATWG가 단일 표준을 제공하기로 합의했습니다.
  • DOM의 4가지 버전: DOM 표준은 현재 4개의 버전이 있습니다.
profile
매일매일 틀깨기

0개의 댓글