DOM 조작 API



DOM 조작 API



지난번 포스트에서 다루었던 DOM 탐색 방법에 대해 기억나십니까?


이번 시간에는 지난 포스트에 이어 노드의 생성, 변경, 삭제에 대해 다뤄보겠습니다.




아래 작성된 함수들을 각각 호출하여 DOM 구조가 어떤 식으로 변경되는지 알아보겠습니다.



해당 소스 수정 및 추가 작성(2012/10/08):

http://jsfiddle.net/zEdAp/1/



var Element = (function (win, doc) {

    var init = function () {
        return this;
    }

    init.prototype = {
        first: first,
        prev: prev,
        next: next,
        last: last,
        attr: attr,
        create: create,
        before: before,
        after: after,
        append: append,
        remove: remove
    };

    return new init();




    // Core
    function first(elem) {

        elem = elem || document.documentElement;

        return elem && elem.nodeType === 1 ? elem.firstChild : next(elem);
    };

    function prev(elem) {

        elem = elem || document.documentElement;

        do {
            elem = elem && elem.previousSibling;
        }
        while (elem && elem.nodeType !== 1)

        return elem;
    };

    function next(elem) {

        elem = elem || document.documentElement;

        do {
            elem = elem && elem.nextSibling;
        }
        while (elem && elem.nodeType !== 1)

        return elem;
    };

    function last(elem) {

        elem = elem || document.documentElement;

        return elem && elem.nodeType === 1 ? elem.lastChild : prev(elem);
    };

    // 속성 가져오기/변경하기
    function attr(elem, args, value) {

        elem = elem || document.documentElement;
        args = args || (args && args.constructor === Object ? {} : '');
        value = value || '';

        if (args.constructor === Object) {

            for (var n in args) {

                var t = { 'for': 'htmlFor', 'class': 'className'}[n] || n;

                elem.setAttribute && elem.setAttribute(t, args[n]);
            }

            return elem;
        }
        else if (args.constructor === String) {

            var t = { 'for': 'htmlFor', 'class': 'className'}[args] || args;

            if (value) {
                elem.setAttribute && elem.setAttribute(t, value);

                return elem;
            }
            else {
                return elem.getAttribute && elem.getAttribute(t) ? elem.getAttribute(t) : '';
            }
        }
    };

    // 객체 생성하기
    function create(tag, opt) {

        tag = tag || '';
        opt = opt || {};

        var elem = document.createElementNS ? document.createElementNS('http://www.w3.org/1999/xhtml', tag) : document.createElement(tag);

        return attr(elem, opt);
    };

    // 객체 속성 존재 여부
    function hasAttr(elem, n) {

        if (!elem) return false;

        n = n || '';

        return elem.getAttribute(n) ? true : false;
    };


    // 해당 객체의 이전 형제로 객체 삽입하기
    function before(before, elem) {

        if (!before || !elem) return null;

        var parent = before && before.parentNode
        , elem = getElement(elem);

        return parent.insertBefore(elem, before);
    };

    // 해당 객체의 이후 형제로 객체 삽입하기
    function after(after, elem) {

        if (!after || !elem) return null;

        var parent = after && after.parentNode
        , elem = getElement(elem);

        return insertAfter(parent, elem, after);
    };


    function insertAfter(parent, elem, after) {
        return after ? parent.insertBefore(elem, after.nextSibling) : append(parent, elem);
    };


    function getElement(elem) {

        if (!elem) return null;

        if (elem.constructor === String) {
            var t = document.createElement('div');
            t.innerHTML = elem;
            elem = t;
        }

        return elem;
    };

    // 해당 객체의 자식 추가
    function append(parent, elem) {

        parent = parent || document.documentElement;
        elem = elem || document.body;

        elem = getElement(elem);

        return parent.appendChild(elem);
    };

    // 해당 객체 삭제
    function remove(elem) {

        var parent = elem && elem.parentNode || document.documentElement;
        elem = elem || document.body;

        return parent.removeChild(elem);
    };

})(window, document);



1. 문서의 첫 번째 div 엘리먼트의 속성을 아래와 같이 변경합니다.


  1. // 함수의 두 번째 매개변수 값으로 각각의 속성이 정의된 객체를 전달하여 호출합니다.
  2.  
  3. Element.attr(document.getElementsByTagName('div')[0], {
  4.     'id': 'test1',
  5.     'name': 'test2',
  6.     'class': 'test3'
  7. });
  8.  
  9. // 함수의 두 번째 매개변수 값으로 객체가 아닌 속성 이름 과 값을 전달하여 정의할 수도 있습니다.
  10. Element.attr(document.getElementsByTagName('div')[0], 'for', 'test4');
  11.  
  12. // 위에서 정의된 엘리먼트의 id속성값을 반환합니다.
  13. alert(Element.attr(document.getElementsByTagName('div')[0], 'id')); // test1





아래는 변경된 엘리먼트의 상태를 나타냅니다.










2. doccument.body 엘리먼트의 자식으로 신규로 생성된 div 엘리먼트를 추가 합니다.


  1. // 두 번째 매개변수 값으로 객체를 추가하여 엘리먼트의 속성을 정의 합니다.
  2. document.body.appendChild(Element.create('div', {'id': 'test1'}));





아래는 변경된 엘리먼트의 상태를 나타냅니다.











3. 해당 엘리먼트(test1)의 자식으로 div 엘리먼트를 추가 합니다.


  1. // 해당 엘리먼트(test1)의 자식으로 div 엘리먼트를 추가 합니다.
  2. var div = document.createElement('div');
  3. div.innerHTML = '<span>div test</span>';
  4.  
  5.  
  6. //Element.append(document.getElementById('test1'), '<div>div test</div>');
  7. Element.append(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.










4. 해당 엘리먼트(test1)의 다음 형제로 div 엘리먼트를 추가 합니다.


  1. var div = document.createElement('div');
  2. div.innerHTML = '<span>div test</span>';
  3.  
  4.  
  5. Element.after(document.getElementById('test1'), '<div><table><tr><td>test</td></tr></table></div>');
  6. Element.after(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.










5. 해당 엘리먼트(test1)의 이전 형제로 div 엘리먼트를 추가 합니다.


  1. var div = document.createElement('div');
  2. div.innerHTML = '<span>div test</span>';
  3.  
  4. Element.before(document.getElementById('test1'), '<div>test2</div>');
  5. Element.before(document.getElementById('test1'), div);





아래는 변경된 엘리먼트의 상태를 나타냅니다.







6. document.body 엘리먼트를 삭제 합니다.


  1. Element.remove(document.body);





아래는 변경된 엘리먼트의 상태를 나타냅니다.



작성된 DOM API를 활용하여 문서가 각각 변경되는 것을 확인해 보았으며, 또한, 위 코드를 개선하여 더욱 효율적인 API를 만들어 보시기 바랍니다.