Javascript Cookbook

일반적이고 재사용 가능한 이벤트 처리 함수 작성하기

문제

DOM 레벨 2 이벤트 핸들링을 구현하고 싶다. 단, 제시한 해결책은 재사용 가능하고 브라우저 호환성 문제도 없어야 한다.

해결

객체 지원 여부에 따라 어떤 함수를 사용할지 결정한다.

function listenEvent(eventTarget, eventType, eventHandler){
    if(eventTarget.addEventListener){
        eventTarget.addEventListener(eventType, eventHandler, false);
    }else if(eventTarget.attachEvent){
        eventType = "on"+eventType;
        eventTarget.attachEvent(eventType, eventHandler);
    }else{
        eventTarget["on"+eventType] = eventHandler;
    }
}
...

listenEvent(document, "click", processClick);

설명

재사용 가능한 이벤트 처리 함수에는 세개의 인수를 전달한다. 세개의 인수는 각각 대상 객체, 이벤트, 함수 이름이다.

addEventListener에 전달되는 마지막 인수는 중첩된 요소의 이벤트를 어떻게 다룰 것인지 가리키는 불리언값이다.

만약 divdocument에 모두 자신의 클릭 이벤트가 있고 세번째 인수에 false로 설정되어 있다면, 이는 곧 바깥쪽 요소 document에서는 이벤트를 캡처하지 않고 중첩된 요소 div를 먼저 처리하고 난 뒤에 document를 처리한다.

하지만 세번째 인수를 true로 설정하면 바깥쪽 요소에서 이벤트를 포착하고 중첩된 요소로 내려가게 된다. div 요소를 클릭하면 document의 클릭 이벤트를 먼저 처리하고 나서 div의 이벤트를 처리한다.

대부분의 경우 안쪽의 중첩된 요소부터 바깥쪽 요소로 이벤트가 올라가기를 원하기 때문에 세번째 인수의 기본값은 false이다.

attachEvent는 마이크로소프트의 IE8에서 지원하는 메서드이다. 이 메서드를 지원하면 이벤트 앞에 on을 붙이고 이벤트와 이벤트 핸들러를 매핑한다.

IE는 위로 오르는 이벤트만 지원하기 때문에 attachEvent는 이벤트의 전파 방향을 정하는 세번째 인수가 없다.

끝으로 addEventListenerattachEvent 둘 다 지원하지 않는 경우에는 DOM 레벨 0 이벤트 핸들링을 사용한다.

DOM 레벨 0 이벤트 핸들링은 객체 이벤트에 이벤트 처리 함수를 할당한다.

document.onclick = 함수이름;

DOM 레벨 0 이벤트 핸들링을 사용할 경우 한개 이상의 자바스크립트 라이브러리를 사용하면 자바스크립트 라이브러리의 이벤트 핸들러를 쉽게 지워버릴 수 있다. 함수 덮어쓰기 문제를 해결할 수 있는 유일한 방법은 사이먼 윌슨이 작성한 다음 코드뿐이다.

function addLoadEvent(func){
    var oldonload = window.onload;
    if(typeof window.onload != 'function'){
        window.onload = func;
    }else{
        window.onload = function(){
            if(oldonload){
                oldonload();
            }
            func();
        }
    }
}

이 함수는 window.onload 이벤트 핸들러에 할당된 것을 변수에 저장한다. 변수의 자료형을 확인해서 함수가 아니면 안전하게 함수를 할당한다. 그렇지만 만약 함수라면 익명함수를 이벤트 핸들러에 할당하고 익명 함수 안에서 그전에 할당한 함수와 우리가 작성한 함수를 실행한다.

그러나 DOM 레벨 2 이벤트 리스너를 사용하면 이미 있는 이벤트 핸들러를 덮어쓰지 않고도 각 라이브러리에서 이벤트 핸들러를 문제없이 추가할 수 있다. 그리고 이벤트는 추가된 순서대로 처리된다.

이벤트 리스닝을 멈추는 함수 작성

이벤트를 멈추는 크로스브라우저 함수는 다음과 같다.

function stopListening(eventTarget, eventType, eventHandler){
    if(eventTarget.removeEventListener){
        eventTarget.removeEventListener(eventType,eventHandler,false);
    }else if(eventTarget.detachEvent){
        eventType = "on"+eventType;
        eventTarget.detachEvent(eventType,eventHandler);
    }else{
        eventTarget["on"+eventType] = null;
    }
}

removeEventListener는 DOM 레벨 2 이벤트 메서드이고 detachEvent는 IE 버전의 DOM 레벨 2 이벤트 메서드이다. 끝으로 removeEventListenerdetachEvent 둘 다 지원하지 않는 경우에는 DOM 레벨 0 이벤트 핸들링을 사용한다.

IE8은 DOM 레벨 2 이벤트 핸들링을 지원하지 않지만 IE9는 지원한다.