※ 이 포스트는 이전 10. DOM - Document Object Model - API 포스트와 이어집니다.

DOM 확장

브라우저 별로 DOM확장을 지원했습니다.
이후 W3C에서 사실상 표준이 된 각종 전용 확장을 명세로 표준화 하기 시작했습니다.
이번 포스트에서는 확장된 DOM 및 각 브라우저 별 전용 확장에 대해 알아봅시다.

선택자 API

jquery는 getElementsById()같은 메서드를 쓰지 않습니다.
완전히 CSS선택자에 기초하여 DOM문서를 쿼리합니다.

하지만 기존에 DOM메서드를 이용해 문서 노드를 이동하며 노드를 골라냈기에 개발자들이 노력을 해도 자바스크립트 코드의 한계를 넘지 못했습니다.

하지만 자바스크립트는 위와같은 동작을 네이티브 API로 구현하여 비약적인 성능향상을 하였습니다.

선택자 API 레벨1의 핵심인 두 메서드를 알아봅시다.

querySelector()메서드

매개변수로 CSS쿼리를 받아 패턴에 일치하는 첫 번째 자손 요소를 반환하며, 없다면 null을 반환합니다.

var body = document.querySelector("body"); //body요소 호출
var idDiv = document.querySelector("#idDiv");    //id가 idDiv인 요소 호출
var classDiv = document.querySelector(".classDiv"); //class가 classIdv인 요소 호출

querySelectorAll() 메서드

위와 같으나 첫번째 자손뿐만아니라 전체 NodeList를 반환합니다.
일치하는 것이 없다면 빈 NodeList를 반환합니다.

//selected클래스 전체 element를 모두 가져옵니다.
var selecteds = document.querySelectorAll(".selected");

for ( var i = 0 ; i < selecteds.length; i++){
    console.log(i);
}

반환된 selecteds는 NodeList이므로 위와같이 for문을 돌릴 수도 있습니다.

matchesSelector()메서드

선택자 API 레벨2 명세에 정의된 메서드입니다.
매개변수로 CSS선택자를 받고 요소가 일치하면 true, 일치하지 않는다면 false를 반환합니다.

<ul>
    <li>Hello</li>
    <li>world</li>
</ul>
//true
console.log(document.querySelector('li').matchesSelector('li:first-child'));

위와같이 li와 li:first-child의 요소가 일치하여 true를 반환하고 있습니다.

요소 간 이동

브라우저 별로 element사이의 공백을 text node로 반환하지 않았습니다.
그런 문제로 childNodes, firstChild같은 프로퍼티는 차이가 발생했습니다.
그래서 DOM명세를 유지하면서 브라우저 사이의 차이를 극복하기 위해 아래와 같은 프로퍼티가 등장했습니다.

  • childElementCount : 자식 element숫자를 반환, 텍스트노드와 주석 제외
  • firstElementChild : 첫 번째 자식요소 확인, firstChild요소와 같음
  • lastElementChild : 마짐가 자식 요소, lastChild요소와 같음
  • previousElementSibling : 이전 형제 요소, previousSibling와 같음
  • nextElementSibling : 다음 형제 요소, nextSibling와 같음

지원하는 브라우저는 이들 프로퍼티를 DOM Element 전체에 추가 합니다.
이를 통해 공백 테스트 노드를 신경쓰지 않고 사용할 수 있습니다.

HTML5

HTML5에서 정의된 DOM 확장에 대해서 알아봅시다.

클래스 관련 추가 사항

class속성을 통해 요소의 시맨틱정보, 스타일정보를 함께 전달하는 사례가 늘었기 때문에 그와 관련해서 여러가지가 바뀌었습니다.

getElementsByClassName() 메서드

이 메서드는 클래스 이름 문자열을 매개변수로 받으며, 해당 클래스를 모두 가진 요소의 NodeList를 반환합니다.

//current클래스와 username클래스가 모두 있는 요소를 찾습니다.
var allCurrentUserName = document.getElementsByClassName("current username");

classList 프로퍼티

클래스 이름을 안전하고 단순하게 조작할 수 있습니다.

var div = document.querySelector("div");

div.classList.remove("user"); //user class이름을 제거합니다.

div.classList.add("current"); //current class이름을 추가 합니다.

div.classList.toggle("user"); //user클래스이름을 토글합니다.

if(div.classList.contains("db")){ //클래스명이 있는지 확인합니다.
    //코드
}

for (var i = 0 ; i < div.classList.length ; i ++){
    console.log(div.classList[i]);
}

포커스 관리

document.activeElement프로퍼티는 항상 현재 포커스를 가진 DOM요소를 가리키는 포인터를 포함합니다.
사용자 입력을 통해 포커스를 받거나 focus()메서드로 자동으로 포커스를 받습니다.

var button = document.getElementById("myButton");
button.focus();
console.log(document.activeElement === button);//true

어느 요소에 포커스가 있는지, 현재 문서에 포커스가 있는지 판단할 수 있기 때문에 중요한 기능입니다.

HTMLDocument의 변화

readyState프로퍼티

readyState프로퍼티는 현재 문서의 상태를 알 수 있습니다.

  • loading : 문서를 불러오는중
  • complete : 문서를 완전히 불러옴

보통 아래와 같이 사용할 수 있습니다.

if(document.readyState == "complete"){
    //코드
}

호환성 모드

IE6에서 표준모드나 쿽스모드로 선택 렌더링하는 방법이 도입된 이후 브라우저에서 페이지를 어떤 모드로 렌더링중인지 알 필요가 생겼습니다.
compatMode라는 프로퍼티로 호환성모드를 확인할 수 있습니다.

if(document.compatMode == "CSS1Compat"){
    //Standards Mode
}else{
    //Quirks Mode
}

head, body프로퍼티

head와 body요소를 가리키는 프로퍼티가 도입되었습니다.

//document.head가 있다면 가져오고 없다면 getElementsByTagName메서드를 사용하는 코드
var head = document.head || document.getElementsByTagName("head")[0];

크롬과 사파리에서 구현되어 있습니다.

문자셋 프로퍼티

HTML5에는 문자셋으 ㄹ다루는 프로퍼티가 여럿 추가되었습니다.

charset프로퍼티는 문서의 문자셋을 나타냅니다. 문자셋 지정도 가능합니다.
defaultCharset프로퍼티는 브라우저 및 시스템의 기본설정에 따라 문서에 기본적으로 적용해야할 문자셋을 나타냅니다.

문서가 기본 문자셋을 사용하지 않을경우 아래와 같이 값이 서로 다를 수 있습니다.

if (document.charset != document.defaultCharset){
    console.log("character set이 다릅니다");
}

커스텀 데이터 속성

커스텀 데이터 속성은 접두사 data-가 붙은 비표준 속성에 제공됩니다.
아래 예제를 봅시다

<div id="myDiv" data-appId="1234" data-myname="Kendrick"></div>
var div = document.getElementById("myDiv");

//값을 가져옵니다.
var appId = div.dataset.appId;
var myName = div.dataset.myname;

//값을 설정합니다.
div.dataset.appId = 222;
div.dataset.myname = "gil";

커스텀 데이터 속성에 dataset프로퍼티를 통해서 접근가능하며
data-접두사를 제거한 이름을 사용하여 접근합니다.

데이터를 연결해야 하지만 사용자에게 보이고싶지 않을 때 유용합니다

마크업 삽입

  • innerHTML : Element의 내부요소를 반환합니다. 설정도 가능합니다.(현재 요소 내부에 추가됨)
  • outerHTML : Element의 요소와 내부요소를 포함해 반환합니다. 설정도 가능합니다.(현재 요소가 교체됨)
  • insertAdjacentHTML() : 두개의 매개변수를 받아서 마크업을 삽입합니다. 첫번째 매개변수는 아래의 값만 넣어주어야 하며, 두번째 매개변수는 삽입할 마크업입니다.
    — beforbegin : 호출한 요소 바로 앞에 삽입
    — afterbegin : 호출한 요소의 첫 번째 자식 요소 바로 앞에 삽입
    — beforeend : 호출한 요소의 마지막 자식 요소 바로 다음에 삽입
    — afterend : 호출한 요소 바로 다음에 삽입

마크업 관련 기능들은 메모리와 성능 문제가 생길 수 있는데 이는 브라우저마다 다릅니다.

scrollIntoView()메서드

스크롤할지에 대해 정의되어있는 메서드입니다.
이 메서드는 모든 HTML요소에 존재하며 브라우저 창이나 컨테이너 요소를 스크롤해서 해당 요소가 뷰 포트에 보이게 합니다.
매개변수로 true를 넘기거나 생략하면 창 전체를 스크롤하여 요소 상단과 뷰포트 상단을 맞춥니다.
그렇지 않다면 뷰포트에서 완전히 보이게하지만 상단을 맞추지는 않습니다.

//body상단으로 뷰포트가 맞춰집니다.
var div = document.body;
div.scrollIntoView();

전용확장

이외에 브라우저 제조사별로 전용 확장을 계속 추가하고 있습니다.
아직 일부 브라우저 전용이지만 중요한 기능이 많이 추가되었으므로 한번 알아보고 갑시다.

문서모드

IE는 문서모드라는 개념을 도입했습니다.
버전별로 지원하는게 다르지만 아래와 같이 정리됩니다.

  • IE5 : 쿽스모드로 렌더링합니다.
  • IE7 : IE7 표준모드로 렌더링합니다. IE8 이상의 기능은 지원 X
  • IE8 : IE8 표준모드로 렌더링합니다. 선택자 API, CSS 2 선택자, CSS3 일부기능을 지원합니다. IE9 기능지원 X
  • IE9 : ECMAScript5, 완전한 CSS3지원, HTML5기능 일부 지원
  • Edge : 문서를 항상 최신문서 모드로 렌더링합니다.
  • EmulateIE9 : 독타입에 따라 9표준 지원, 그렇지 않다면 IE5에 맞춥니다.
  • EmulateIE8 : 독타입에 따라 8표준 지원, 그렇지 않다면 IE5에 맞춥니다.
  • EmulateIE7 : 독타입에 따라 7표준 지원, 그렇지 않다면 IE5에 맞춥니다.
  • 9 : 9로 강제
  • 8 : 8로 강제
  • 7 : 7로 강제
  • 5 : 5로 강제

innerText, outerText

innerHTML, outerHTML과 달리 아직 표준으로 정해지지않았습니다.
텍스트요소만 반환합니다.

마치며

DOM확장은 웹기술 발전에 따라서 계속 늘어날 것입니다.
다음 포스트에서는 DOM 레벨 2, 레벨3에 대해서 간단히 알아보겠습니다.