Skip to content

Latest commit

 

History

History
618 lines (489 loc) · 18.1 KB

39.7-9_study_jsi.md

File metadata and controls

618 lines (489 loc) · 18.1 KB

39장 DOM


39.7 어트리뷰트

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

✅ HTML 요소의 동작 제어 목적으로 추가적인 정보를 제공합니다.

39-70

<HTML요소시작태그 어트리뷰트이름="어튜리뷰트값" />
<input id="user" type="text" value="ungmo2" />

🤔 어트리뷰트 종류

  • 글로벌 어트리뷰트: id, class, style, title, lang, tabindex, draggable, hidden 등
  • 이벤트 핸들러 어트리뷰트: onclick, onchange, onfocus, onblur, oninput, onkeypress, onkeydown, onkeyup, onmouseover, onsubmit, onload 등
  • 특정 HTML 요소 어트리뷰트: 예) input: type, value, checked

😀 HTML 문서 파싱 시 HTML 어트리뷰트당 하나의 어트리뷰트 노드로 변환되어 요소 노드와 연결됩니다.

🤔 NamedNodeMap 객체

  • 요소 노드의 모든 어트리뷰트 노드의 참조가 담긴 이터러블한 유사 배열 객체입니다.
  • attributes 프로퍼티에 저장되어있습니다. (getter만 존재 하는 읽기 전용 접근자 프로퍼티) 요소 노드의 attributes 프로퍼티

39-71

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      const { attributes } = document.getElementById("user");
      console.log(attributes);
      // NamedNodeMap {0: id, 1: type, 2: value, id: id, type: type, value: value, length: 3}

      console.log(attributes.id.value); // user
      console.log(attributes.type.value); // text
      console.log(attributes.value.value); // ungmo2
    </script>
  </body>
</html>

39.7.2 HTML 어트리뷰트 조작

🤔 Element.protype.getAttribute/setAttribute 메서드

  • 직접 HTML 어트리뷰트 값을 취득하거나 변경할 수 있습니다.

39-72

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      const $input = document.getElementById("user");

      // value 어트리뷰트 값을 취득
      const inputValue = $input.getAttribute("value");
      console.log(inputValue); // ungmo2

      // value 어트리뷰트 값을 변경
      $input.setAttribute("value", "foo");
      console.log($input.getAttribute("value")); // foo
    </script>
  </body>
</html>

🤔 Element.protype.hasAttribute/removeAttribute 메서드

  • hasAttribute: 특정 HTML 어트리뷰트의 존재를 확인할 수 있습니다.
  • removeAttribute: 특정 HTML 어트리뷰트를 삭제할 수 있습니다.

39-73

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      const $input = document.getElementById("user");

      // value 어트리뷰트의 존재 확인
      if ($input.hasAttribute("value")) {
        // value 어트리뷰트 삭제
        $input.removeAttribute("value");
      }

      console.log($input.hasAttribute("value")); // false
    </script>
  </body>
</html>

39.7.3 HTML 어트리뷰트 vs. DOM 프로퍼티

🤔 DOM 프로퍼티

  • 요소 노드 객체가 가지고 있는 HTML 어트리뷰트에 대응하는 프로퍼티
  • HTML 어트리뷰트 값이 초기값입니다. HTML 요소에 대응하는 요소 노드의 프로퍼티
  • setter와 getter 모두 존재 하는 접근자 프로퍼티입니다.

  • 요소 노드는 상태(state)를 가집니다.
  • 어트리뷰트 노드: 초기 상태
  • DOM 프로퍼티: 최신 상태

🤔 어트리뷰트 노드

  • getAttribute, setAttribute 메서드 사용하여 초기 상태 값을 취득하거나 변경합니다.

39-77

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      document.getElementById("user").getAttribute("value"); // ungmo2
      document.getElementById("user").setAttribute("value", "foo");
    </script>
  </body>
</html>

🤔 DOM 프로퍼티

  • 사용자의 입력에 의한 상태 변화에 반응하여 언제나 (동적으로 변경) 최신 상태 를 유지합니다.

39-78

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      const $input = document.getElementById("user");

      // 사용자가 input 요소의 입력 필드에 값을 입력할 때마다 input 요소 노드의
      // value 프로퍼티 값, 즉 최신 상태 값을 취득한다. value 프로퍼티 값은 사용자의 입력에
      // 의해 동적으로 변경된다.
      $input.oninput = () => {
        console.log("value 프로퍼티 값", $input.value); // DOM 프로퍼티 값
      };

      // getAttribute 메서드로 취득한 HTML 어트리뷰트 값, 즉 초기 상태 값은 변하지 않고 유지된다.
      console.log("value 어트리뷰트 값", $input.getAttribute("value")); // 어트리뷰트 값
    </script>
  </body>
</html>

39-79

<!DOCTYPE html>
<html>
  <body>
    <input id="user" type="text" value="ungmo2" />
    <script>
      const $input = document.getElementById("user");

      // DOM 프로퍼티에 값을 할당하여 HTML 요소의 최신 상태를 변경한다.
      $input.value = "foo";
      console.log($input.value); // foo

      // id 어트리뷰트와 id 프로퍼티는 사용자 입력과 관계없이 항상 동일한 값으로 연동한다.
      $input.id = "foo";

      // getAttribute 메서드로 취득한 HTML 어트리뷰트 값, 즉 초기 상태 값은 변하지 않고 유지된다.
      console.log($input.getAttribute("value")); // ungmo2
      console.log($input.id); // foo
      console.log($input.getAttribute("id")); // foo
    </script>
  </body>
</html>

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

  • id 어트리뷰트와 id 프로퍼티는 1:1 대응하며, 동일한 값으로 연동합니다.
  • input 요소의 value 어트리뷰트와 value 프로퍼티는 1:1 대응하며,
    value 어트리뷰트는 초기 상태를, value 프로퍼티는 최신 상태를 가집니다.
  • class 어트리뷰트는 className, classList 프로퍼티와 대응합니다.
  • for 어트리뷰트는 htmlFor 어트리뷰트 프로퍼티와 1:1 대응합니다.
    예외
  • td 요소의 cospan 어트리뷰트는 대응하는 프로퍼티가 존재하지 않습니다.
  • textContent 프로퍼티는 대응하는 어트리뷰트가 존재하지 않습니다.
  • 어트리뷰트 이름은 대소문자를 구별하지 않지만 대응하는 프로퍼티 키는 카멜 케이스를 따릅니다. (maxlength -> maxLength)

DOM 프토퍼티 값의 타입 은 문자열이 아닐 수 있다.

39-81

<!DOCTYPE html>
<html>
  <body>
    <input type="checkbox" checked />
    <script>
      const $checkbox = document.querySelector("input[type=checkbox]");

      // getAttribute 메서드로 취득한 어트리뷰트 값은 언제나 문자열이다.
      console.log($checkbox.getAttribute("checked")); // ''

      // DOM 프로퍼티로 취득한 최신 상태 값은 문자열이 아닐 수도 있다.
      console.log($checkbox.checked); // true
    </script>
  </body>
</html>

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

🤔 data 어트리뷰트

  • data- 접두사
  • 사용자 정의 어트리뷰트와 자바스크립트 간에 데이터를 교환할 수 있습니다.

🤔 dataset 프로퍼티

  • HTML 모든 요소 data 어트리뷰트의 정보를 제공하는 DOMStringMap 객체를 반환합니다.
  • 카멜 케이스로 변환

39-83

<!DOCTYPE html>
<html>
  <body>
    <ul class="users">
      <li id="1" data-user-id="7621" data-role="admin">Lee</li>
      <li id="2" data-user-id="9524" data-role="subscriber">Kim</li>
    </ul>
    <script>
      const users = [...document.querySelector(".users").children];

      const user = users.find((user) => user.dataset.userId === "7621");
      console.log(user.dataset.role); // "admin"

      user.dataset.role = "subscriber";
      // dataset 프로퍼티는 DOMStringMap 객체를 반환한다.
      console.log(user.dataset); // DOMStringMap {userId: "7621", role: "subscriber"}
    </script>
  </body>
</html>

존재하지 않는 이름을 키로 사용하여 dataset 프로퍼티에 할당HTML 요소에 data 어트리뷰트가 추가 됩니다.

39-84

<!DOCTYPE html>
<html>
  <body>
    <ul class="users">
      <li id="1" data-user-id="7621">Lee</li>
      <li id="2" data-user-id="9524">Kim</li>
    </ul>
    <script>
      const users = [...document.querySelector(".users").children];
      const user = users.find((user) => user.dataset.userId === "7621");

      user.dataset.role = "admin";
      console.log(user.dataset);
      /*
    DOMStringMap {userId: "7621", role: "admin"}
    -> <li id="1" data-user-id="7621" data-role="admin">Lee</li>
    */
    </script>
  </body>
</html>

39.8 스타일

39.8.1 인라인 스타일 조작

🤔 HTMLElement.prototype.style 프로퍼티

  • getter, setter 모두 존재 하는 접근자 프로퍼티
  • 요소 노드의 인라인 스타일 을 취득하거나 추가 또는 변경

39-85

<!DOCTYPE html>
<html>
  <body>
    <div style="color: red">Hello World</div>
    <script>
      const $div = document.querySelector("div");

      // 인라인 스타일 취득
      console.log($div.style); // CSSStyleDeclaration { 0: "color", ... }

      $div.style.color = "blue";

      // 인라인 스타일 추가
      $div.style.width = "100px";
      $div.style.height = "100px";
      $div.style.backgroundColor = "yellow";
    </script>
  </body>
</html>

🤔 CSSStyleDeclaration

  • style 프로퍼티 참조시 CSSStyleDeclaration 타입의 객체를 반환합니다.
  • 다양한 CSS 프로퍼티에 대응하는 프로퍼티
  • 값 할당 시 해당 CSS 프로퍼티가 인라인 스타일로 HTML 요소에 추가되거나 변경됩니다.
  • ❗CSS 프토퍼티는 케밥 케이스, CSSStyleDeclaration 객체의 프로퍼티는 카멜 케이스를 따릅니다.

39-86

$div.style.backgroundColor = "yellow"; // CSSStyleDeclaration 객체의 프로퍼티
$div.style["background-color"] = "yellow"; // 케밥 케이스의 CSS 프로퍼티 사용 시 작성방법
$div.style.width = "100px"; // 단위 지정이 필요한 CSS 프로퍼티 값은 반드시 지정

39.8.2 클래스 조작

  • 클래스 DOM 프로퍼티: classNameclassList

    자바스크립트에서는 class 예약어

🤔 className

  • settergetter 모두 존재 하는 접근자 프로퍼티
  • HTML 요소의 class 어트리뷰트 값을 취득하거나 변경
  • 문자열을 반환하기 때문에 공백으로 구분된 여러 개의 클래스를 반환하는 경우 불편

39-89

<!DOCTYPE html>
<html>
  <head>
    <style>
      .box {
        width: 100px;
        height: 100px;
        background-color: antiquewhite;
      }
      .red {
        color: red;
      }
      .blue {
        color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box red">Hello World</div>
    <script>
      const $box = document.querySelector(".box");
      console.log($box.className); // 'box red'
      $box.className = $box.className.replace("red", "blue");
    </script>
  </body>
</html>

🤔 classList -> DOMTokenList 객체

  • class 어트리뷰트 정보를 담은 DOMTokenList 객체를 반환
  • 컬랙션 객체로서 유사 배열 객체이면서 이터러블

39-90

<!DOCTYPE html>
<html>
  <head>
    <style>
      .box {
        width: 100px;
        height: 100px;
        background-color: antiquewhite;
      }
      .red {
        color: red;
      }
      .blue {
        color: blue;
      }
    </style>
  </head>
  <body>
    <div class="box red">Hello World</div>
    <script>
      const $box = document.querySelector(".box");

      // .box 요소의 class 어트리뷰트 정보를 담은 DOMTokenList 객체를 취득
      // classList가 반환하는 DOMTokenList 객체는 HTMLCollection과 NodeList와 같이
      // 노드 객체의 상태 변화를 실시간으로 반영하는 살아 있는(live) 객체다.
      console.log($box.classList);
      // DOMTokenList(2) [length: 2, value: "box blue", 0: "box", 1: "blue"]

      // .box 요소의 class 어트리뷰트 값 중에서 'red'만 'blue'로 변경
      $box.classList.replace("red", "blue");
    </script>
  </body>
</html>

✅ 메서드

add(...className)

// class="box red"
$box.classList.add("foo"); // -> class="box red foo"
$box.classList.add("bar", "baz"); // -> class="box red foo bar baz"

remove(...className)

// class="box red bar baz"
$box.classList.remove("foo"); // -> class="box red bar baz"
$box.classList.remove("bar", "baz"); // -> class="box red"
$box.classList.remove("x"); // 무시 -> class="box red"

item(index)

// class="box red"
$box.classList.item(0); // -> "box"
$box.classList.item(1); // -> "red"

contains(className)

// class="box red"
$box.classList.contains("box"); // -> true
$box.classList.contains("blue"); // -> false

replace(oldClassName, newClassName)

// class="box red"
$box.classList.replace("red", "blue"); // -> class="box blue"

toggle(className[, force])

  • 인수로 전달한 문자열과 일치하는 클래스가 존재하면 제거, 존재하지 않으면 추가합니다.
class="box blue"
$box.classList.toggle("foo"); // -> class="box blue foo"
$box.classList.toggle("foo"); // -> class="box blue"
  • 두번째 인수 설정
  • 조건식 평가 결과가 true이면 강제로 첫 번째 인수로 받은 문자열을 추가하고, false이면 강제로 첫 번째 인수로 전달받은 문자열을 제거합니다.
// class 어트리뷰트에 강제로 'foo' 클래스를 추가
$box.classList.toggle("foo", true); // -> class="box blue foo"
// class 어트리뷰트에서 강제로 'foo' 클래스를 제거
$box.classList.toggle("foo", false); // -> class="box blue"

이 밖에 forEach, entries, keys, value, supports 메서드를 제공합니다.

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

🤔 getComputedStyle(element[, pseudo]):

  • 모든 CSS 스타일 참조
  • 첫 번째 인수로 전달한 요소 노드에 적용되어 있는 평가된 스타일을 getComputedStyle 객체에 담아 반환합니다.

    링크 스타일, 임베딩 스타일, 인라인 스타일, 자바스크립트에서 적용한 스타일, 상속된 스타일, 기본(user agent) 스타일 등 모든 스타일 조합

39-98

<!DOCTYPE html>
<html>
  <head>
    <style>
      body {
        color: red;
      }
      .box {
        width: 100px;
        height: 50px;
        background-color: cornsilk;
        border: 1px solid black;
      }
    </style>
  </head>
  <body>
    <div class="box">Box</div>
    <script>
      const $box = document.querySelector(".box");

      // .box 요소에 적용된 모든 CSS 스타일을 담고 있는 CSSStyleDeclaration 객체를 취득
      const computedStyle = window.getComputedStyle($box);
      console.log(computedStyle); // CSSStyleDeclaration

      // 임베딩 스타일
      console.log(computedStyle.width); // 100px
      console.log(computedStyle.height); // 50px
      console.log(computedStyle.backgroundColor); // rgb(255, 248, 220)
      console.log(computedStyle.border); // 1px solid rgb(0, 0, 0)

      // 상속 스타일(body -> .box)
      console.log(computedStyle.color); // rgb(255, 0, 0)

      // 기본 스타일
      console.log(computedStyle.display); // block
    </script>
  </body>
</html>

실행결과

  • 의사 요소를 지정하는 문자열을 전달할 수 있다.
  • 의사 요소가 아닌 일반 요소의 경우 두 번째 인수는 생략한다.

39-99

<!DOCTYPE html>
<html>
  <head>
    <style>
      .box:before {
        content: "Hello";
      }
    </style>
  </head>
  <body>
    <div class="box">Box</div>
    <script>
      const $box = document.querySelector(".box");
      const computedStyle = window.getComputedStyle($box, ":before");
      console.log(computedStyle.content); // "Hello"
    </script>
  </body>
</html>

39.9 표준

  • W3C가 WHATWG가 만든 HTML과 DOM의 공통된 표준
  • 2018년 4월, 구글, 애플, 마이크로소프트, 모질라로 구성된 WHATWG이 만드는 단일 표준
레벨 표준 문서 URL
DOM Level 1 https://www.w3.org/TR/REC-DOM-Level-1
DOM Level 2 https://www.w3.org/TR/DOM-Level-2-Core
DOM Level 3 https://www.w3.org/TR/DOM-Level-3-Core
DOM Level 4 https://dom.spec.whatwg.org