Document Object Model

웹페이지를 Javascript로 제어하기 위한 객체 모델. window 객체의 document 프로퍼티를 통해서 사용할 수 있다.

제어 대상을 찾기

제어의 대상을 찾은 후 그 대상에 대해 작업을 한다.

document.getElementsByTagName : 태그의 이름을 통해 엘리먼트'들'을 가져온다.

var lis = document.getElementsByTagName('li');
for(var i=0; lis.length; i++) {
    lis[i].style.color='red';
}

-> li 태그를 갖는 엘리먼트들을 받아와 NodeList라는 유사배열에 리턴한다.

만약에 모든 li 태그가 아니라 특정 태그 안에 속해있는 li 태그만을 가져오고 싶다면??

<html>
<body>
<ul>
    <li>html</li>
    <li>css</li>
</ul>
<ol>
    <li>html</li>
    <li>css</li>
</ol>
<script>
    var ul = document.getElementByTagName('ul')[0];
    var lis = ul.getElementByTagName('li');
    for( ) { }
</script>

-> 위와 같이 ul 태그를 먼저 가져오고, 그 ul 객체를 이용해서 li 태그를 불러오는 방식으로 한다. (첫번째 ul 태그를 가져오기 위해 인덱스에 [0]으로 한 것도 확인!)

document.getElementsByClassName : 클래스 속성의 값을 기준으로 객체를 조회

<li class="active">css</li>
</ul>
<script>
    var lis = document.getElementsByClassName('active');
</script>

document.getElementById : Id 값을 기준으로 객체를 조회 (ID값은 하나이기 때문에 elements가 아니라 element임) [가장 성능이 좋음]

document.querySelector : css 선택자의 문법을 이용해서 객체를 조회할 수도 있다. (하나의 결과만 리턴)

var li = document.querySelector('li'); // All tags of li
var li = document.querySelector('.active'); // All tags with class name is active

document.querySeletorAll : 모든 결과를 리턴해서 유사배열에 담음

jQuery의 사용

jQuery( document ).ready(function($) {
    $('body').prepand('<h1>Hello world</h1>');
});

-> body 태그 앞에 <h1>hello world<\/h1> 태그를 끼워넣는 구문. (일단 jQuery 부분은 이해하지 않고 넘어감)

jQuery를 사용한 제어 대상 찾기

$()는 jQuery의 함수이다. 이 함수의 인자로 CSS 선택자가 들어오면 jQuery 객체를 리턴 (즉, $('li)는 jQuery 객체!)한다. 이 리턴된 객체는 선택자에 해당하는 엘리먼트를 제어하는 다양한 메소드를 가지고 있다. 위 예제는 li 태그 객체들을 red로 변경하는 css method를 이용한 것이다.

  • $('li') -> li tag를 검색할 때

  • $('.active') -> class name이 active인 것을 검색할 때

  • $('#active') -> id 값이 active인 것을 검색할 때

Chaining : $('$active').css('color', 'red').css('textDecoration', 'underline'); 처럼 한 객체에 대해 여러 메소드를 사용하는것

getElement* method를 통해서 리턴된 객체가 무엇인지 알아본다

[객체].constructor.name 통해 객체의 이름을 알 수 있다.

HTMLElement : 객체가 1개만 리턴될 때

하지만 각 태그별로 리턴되는 객체가 조금씩 다르다. 예를 들어 li 태그는 HTMLLIElement, a 태그는 HTMLAnchorElement, Input 태그는 HTMLInputElement다 (모두 HTMLElement의 자식 객체!). 그리고 각 객체가 가지고 있는 프로퍼티가 다르다.

즉, HTMLElement의 공통적인 프로퍼티를 상속 받고, 각각의 특징은 각 개체가 따로 구현해놓은 것.

각 요소들의 부모-자식 관계를 나타낸 것이 Dom tree이고, 그 구조는 다음과 같다

HTMLCollection : 객체가 여러개 리턴될 때

유사 배열에 리턴이 된다. 그리고 배열에서 한 객체를 지우거나 추가했을 때 HTMLCollection의 목록은 실시간으로 변경된다.

jQuery 객체

암시적 반복 : $('li').css('text-decoration', 'underline');을 하는 경우, 모든 li tag를 순회하며 css 효과를 주는 것을 말한다.

css method에서 두번째 인자의 값이 없다면 첫번째 인자에 해당하는 속성의 값을 가져온다. 그러나 이 경우에는 첫번째 엘리먼트의 값만 가져온다. (ex, .css('text-decoration') )

그럼 두, 세번째에 접근하는 방법은?

var li = $('li');
li.length, li[0], li[1], ....

※ 주의할 점 : 이 리턴된 li[0], li[1] 객체들은 jQuery 객체가 아니라 DOM 객체이다. 따라서 이 객체를 제어하려면 jQuery 함수를 이용해야 한다.

li[0].css('color', 'red'); --> Undefined error !!!
$(li[0]).css('color', 'red'); ---> Working correctly !!!

map method의 이용

var li = $('li');
li.map(function(index, elem) {
    console.log(index, elem);
    $(elem).css('color', 'red');
})

-> map 함수는 jQuery 객체를 통해 나온 결과를 하나씩 돌면서 인자로 받은 함수를 실행한다. 여기서는 Index와 해당 DOM 객체를 인자로 받아 css를 바꾸는 함수를 인자로 넣었다.

Element 객체

DOM은 HTML 만을 프로그래밍적으로 제어하기 위한 규격이 아니다. XML, SVG, XUL과 같이 마크업 형태의 언어를 모두 제어하기 위한 규격이기 때문에 Element는 마크업 언어의 일반적인 규격에 대한 속성을 정의하고 있고, 각각 구체적인 언어를 위한 기능은 HTMLElement, SVGElement, XULElement와 같은 객체를 통해서 추가해서 사용하고 있다.

-Element의 주요기능

  • 식별자 : Element.classList, Element.className, Element.id, Element.tagName

  • 조회 : Element.getElementByClassName, Element.getElementsByTagName, Element.querySelector, Element.querySelectorAll

  • 속성 : Element.getAttribute(name), setAttribute(name, value), hasAttribute(name), removeAttribute(name)

-식별자 API 엘리먼트를 제어하기 위해서는 그 엘리먼트를 조회하기 위한 식별자가 필요하다. HTML에서 엘리먼트의 이름과 id 그리고 class는 식별자로 사용된다. 식별자 API는 이 식별자를 가져오고 변경하는 역할을 한다.

document.getElementById('active').tagName ;

-> active라는 id를 가지는 Element (지금은 HTMLElement)의 태그 이름을 가져온다. (읽기전용, 변경불가능)

document.getElementById('active').id ;

-> 각 엘리먼트를 식별하는 단 하나의 식별자. 단 하나만 존재할 수 있음. (변경 가능)

document.getElementById('active).className ;

-> 여러개의 엘리먼트를 그룹핑하는 Class 이름을 가져온다. (변경 가능)

단점 ; class 를 추가하려면 += " CLASSNAME"처럼 해야된다. (추가\/제거가 불편함) \/\/ HTML 태그에 class는 공백으로 구분된다.

ex, <li id="active" class="marked current important"> <\/li> -> class가 3개 : marked, current, important

var active = document.getElementById('active);
active.classList.add('marked'); // add class
active.classList.remove('important'); // remove class
active.classList.toggle('current'); // toggle (on/off) class

-> classList 속성을 이용하여 편리하게 클래스 추가\/제거가 가능하다.

-조회 API

엘리먼트를 조회하는 기능. getElements* 들은 충분히 봤다! 그러므로 이번에는 조회 대상을 제한하는 방법에 대한 것!

어떤 객체의 하위 엘리먼트만 조회하고 싶을 때.

ex, id 값이 'active' 하위의 class이름이 'marked'인 엘리먼트만을 조회하고 싶을 때

var active = document.getElementById('active');
var list = active.getElementsByClassName('marked); // document -> active -> className = 'marked'

-속성 API

var t = document.getElementById('target'); // get element with id is 'target'
t.getAttribute('href'); // get value of href attribute
t.setAttribute('href','http://naver.com'); // set value of href to naver.com
t.removeAttribute('href'); // remove href attribute
t.hasAttribute('href');
var target = document.getElementById('target');
target.setAttribute('class', 'important'); // attribute 방식
target.className = 'important'); // property 방

HTML tag상 property 접근

class className
readonly readOnly
rowspan rowSpan
colspan colSpan
usemap userMap
frameborder frameBorder
for htmlFor
maxlength maxLength

※ 가끔 프로퍼티로 접근할 때와 속성 method를 통해 접근할 때의 값이 서로 다를 수가 있다.

(ex, target.href \/ target.getAttribute('href') 는 같은 기능이지만 하나는 절대경로, 다른 하나는 상대경로를 가져올 수 있다.)

-jQuery 속성 제어 API

jQuery 객체의 메소드 중 setAttribute, getAttribute에 대응되는 메소드는 attr이고 removeAttribute에 대응되는 메소드는 removeAttr이다.

var t= $('target');
t.attr('href');
t.attr('href', 'http://www.naver.com');
t.removeAttr('href');
var t1 = $('#t1');
t1.attr('href'); // attribute 방식 -> 상대경로
t1.prop('href'); // property 방식 -> 절대경로

jQuery에서는 DOM에서와는 다르게 프로퍼티의 이름으로 어떤 것을 사용하건 올바른 것으로 교정해준다. 이것이 라이브러리의 장점

$('#t1').prop('className', 'important');
$('#t2').prop('class', 'current');

-jQuery 조회 범위 제한

getElement*를 두, 세 단계로 할 필요 없이 CSS처럼 하면 된다.

$("#active .marked").css("background-color", "red");
$(".marked", "#active").css("background-color", "red");

-> id가 active 하위의 class 이름이 marked인 엘리먼트들을 대상으로 작동

.find() method : jQuery 객체 내에서 엘리먼트를 조회하는 메소드

$("#active").find('.marked').css("background-color", "red"); // chaining
$("#active").css('color', 'blue').find('.marked').css("background-color", "red");
// id with 'active' = color blue and element with active -> marked = background color red

-> active 하위에 있는 애들도 글씨색이 blue로 바뀐다..

Node 객체

DOM tree의 최상단에 위치하는 객체. 모든 DOM 객체들은 Node 객체를 상속 받는다.

-Node의 주요기능

  • 관계 : 엘리먼트는 서로 부모, 자식 혹은 형제 자매 관계로 연결되어 있다. 각각의 Node가 다른 Node와 연결된 정보를 보여주는 API ( Node.childNodes, firstChild, lastChild, nextSibling, previousSibling, contains, hasChildNodes )

  • 노드 종류 : Node는 모든 구성요소를 대표하는 객체이므로 각각의 구성요소가 어떤 카테고리에 속하는지 식별해주는 API ( Node.nodeType, nodeName )

  • 값 : Node 객체의 값 ( Node.nodeValue, textContent )

  • 자식 관리 : 객체의 자식을 추가\/제거하는 방법에 대한 API ( Node.appendChild, removeChild )

-Node 관계 API

<body id="start">
<ul>
    <li><a href="">html</a></li>
    <li><a href="">css</a></li>
        <ul>
            <li><a href="">Javascript</a></li>
            <li><a href="">DOM</a></li>
        </ul>
    </li>
</ul>
<script>
var s = document.getElementById('start');
console.log( s.firstChild ); // #Text
var ul = s.firstChild.nextSibling; // ul

-> body 태그와 ul 태그 사이에 공백 or 줄바꿈이 있기 떄문에 s.firstChild의 결과가 Text 객체가 나오는것이다! (ul태그라고 생각하기 쉬운 케이스)

-Node 종류 API

현재 선택한 노드가 어떤 타입, 태그명이 무엇인지를 판단하는 API (타입 - nodeType, 태그명 - nodeName)

recursive function을 이용해서 부모->자식 노드를 조회할때 노드의 특정 타입, 태그명만을 골라서 원하는 기능을 구현할 수 있음

function traverse(target, callback){
    if(target.nodeType === Node.ELEMENT_NODE){
        if(target.nodeName === 'A')
            callback(target);
    }
    var c = target.childs;
    for(var i = 0; i < c.length; i++){
        traverse(c[i], callback);
}
traverse(document.getElementById('start'), function(elem){ console.log(elem) });

-Node 변경 API

  • 노드 추가 API (appendChild, insertBefore)

※ 노드를 추가하기 위해서는 추가할 엘리먼트를 생성해야 하는데 이것은 Node가 아니라 document 객체의 기능이다. (document.createElement, document.createTextNode)

<body>
<ul id='target'>
    <li>HTML</li>
    <li>CSS</li>
</ul>
<input type="button" onclick="callAppendChild();" value="appendChild()" /> 
<input type="button" onclick="callInsertBefore();" value="insertBefore()" /> 
<script>
    function callAppendChild(){
        var target = document.getElementById('target');
        var li = document.createElement('li');
        var text = document.createTextNode('Javascript');
        li.appendChild(text);
        target.appendChild(li);
    }

-> 'CSS' list 뒤에 Javascript라는 list를 하나 더 추가하고 싶은 것이 목적이다. 이 때, li 태그를 생성하고, Javascript라는 텍스트를 담고 있는 TextNode를 생성하는게 전부가 아니다. 그 둘을 붙여주는 li.appendChild(text)가 있어야한다.

  • 노드 제거 API (removeChild)

※ 삭제 대상의 부모 노드 객체의 메소드를 실행해야 한다

ex, target을 지우고 싶다면..

var target = document.getElementById('target');
target.parentNode.removeChild(target);

-> 삭제하려는 대상도 알아야되고, 삭제하려는 대상의 부모도 알아야되는 불편한 점이 있다.

  • 노드 변경 API (replaceChild)

노드의 내용을 변경하는 API (replaceChild)

<li id="target">Javascript</li>
<script>
    function callReplaceChild(){
        var a = document.createElement('a');
        a.setAttribute('href', 'http://www.naver.com');
        a.appendChild(document.createTextNode('Web browser JavaScript');

        var target = document.getElementById('target');
        target.replaceChild(a, target.firstChild);
    }
</script>

-> a 태그 생성. a 태그에 속성 부여, a 태그 내부에 텍스트 노드 생성 후에 appendChild로 붙여줌. 이후 li 태그 객체를 가져온 후에 li 태그의 firstChild, 즉 'Javascript'라는 텍스트노드를 replace 하는 과정

-jQuery Node 변경 API (Manipulation category)

  • 노드 추가 API (before, prepend, append, after)

before : 제어 대상의 형제 노드 형태로 앞에

prepend : 제어 대상의 자식 노드 형태로 content 앞에

append : 제어 대상의 자식 노드 형태로 content 뒤에

after : 제어 대상의 형제 노드 형태로 뒤에

  • 노드 제거 API (remove, empty)

remove : 제어 대상을 제거하는 것 empty : 제어 대상의 텍스트 노드를 제거하는 것

  • 노드 변경 API (replaceWith, replaceAll)

replaceWith : 제어대상을 먼저 지정 ( $('#target2').replaceWith('<div>replaceWith<\/div>'); ) replaceAll : 제어대상이 되는 것을 인자로 전달 ( $('<div>replaceAll<\/div').replaceAll('#target1'); )

-> 둘다 #target1, #target2 엘리먼트에 <div>태그의 내용을 집어 넣는 방법이다.

  • 노드 복사 API
$('#source').clone().replaceAll('#target1');
$('#target2').replaceWith($('#source').clone());

-> source를 복사해서 target1, target2를 대체하는 코드.

  • 노드 이동 API
$('#target1').append($('#source'));
append, prepend, before, after 가

-> source를 target1 엘리먼트 뒤로 이동한다.

-문자열로 노드 제어

  • innerHTML : 선택한 element 미포함 하위 엘리먼트를 보여줌
var target = document.getElementById('target');
target.innerHTML = "<li>Javascript core</li><li>BOM</li><li>DOM</li>";
  • outerHTML : 선택한 element 포함 하위 엘리먼트를 보여줌

  • innerText, outerText : 보여줄 때는 태그 없이, 바꿀 때는 태그 내용 인식 없이 텍스트 그대로 변경

  • insertAdjacentHTML : 좀 더 정교하게 문자열을 이용해서 노드를 변경하고 싶을 때 사용
<ul id="target">
    <li>CSS</li>
</ul>
var target = document.getElementById('target');
target.insertAdjacentHTML('beforebegin', '<h1>Client side</h1>');
target.insertAdjacentHTML('afterbegin', '<li>HTML</li>');
target.insertAdjacentHTML('beforeend', '<li>Javascript</li>');
target.insertAdjacentHTML('afterend', '<h1>Server side</h1>');

beforebegin : 선택한 엘리먼트가 시작되기 전에 (ul 태그 위에)

afterbegin : 선택한 엘리먼트가 시작된 후에 (ul 태그 바로 다음에, CSS li 태그 위에)

beforeend : 선택한 엘리먼트가 끝나기 전에 (<\/ul> 태그 바로 위에, CSS li 태그 다음에)

afterend : 선택한 엘리먼트가 끝난후에 (<\/ul> 태그 바로 다음에)

results matching ""

    No results matching ""