2007년 11월 15일
자바스크립트 이벤트 핸들링 및 클래스간 메시징 지원
시스템이 모듈화 되어 갈수록, 대형화 되고 복잡도가 높아 질수록 모듈간의 통신 방법이 필요합니다.
기존에는 직접적인 메소드 호출을 하였지만, 이는 모듈간 의존도를 높여서 재활용성을 저해하고 자유로운 시스템의 재구성 및 계층화를 하기 힘들게 합니다.
그래서, 각 프로그래밍 언어 또는 프레임웍들은 나름대로 모듈간 통신 방법을 제공합니다.
[간단한 이벤트 핸들러 정의]
HTML에서는 이벤트라는 것을 제공합니다. 그러나, 이것이 모듈간의 통신 방법이 아니라 발생한 이벤트에 대한 통지라는 점이 문제가 있습니다.
SWAF 초기버전에서는 모듈간의 메시징을 위해 이것과 별개로 메시지를 지원하여 클래스간 통신을 하도록 하였습니다. 그러나, 브라우져에서 발생하는 UI이벤트들에 대한 처리와 별개로 되어 있어 실제 활용도가 떨어졌습니다.
그래서, SWAF2에서는 이것들을 일원화 하였습니다. 특히, SWAF에서 제공하는 클래스에 이벤트를 정의하여 그 활용도를 극대화 할 수 있게 되었습니다. MFC에서 제공하던 UI 클래스들을 SWAF에서도 만들어서 널리 재사용할 수 있게 될 것이라고 기대합니다.
물론, 기존 버전과 같은 단순 형태의 이벤트 매핑도 제공합니다. 사용법은 아래와 같습니다.
$listener(element,event_name,listener,[owner])
특히 element는 1개의 element가 아니라 여러개의 element도 지정할 수 있어 여러개의 이벤트 핸들러를 하나로 지정할 때 무척 편리합니다. 사용 예는 아래와 같습니다.
$listener( $('btn1'), 'click', onClickBtn1 );
$listener( $('#a',$('menu_root')), 'click', onClickMenu );
$listener( $(/btn_+/), 'click', onClickBtn );
단, $listener는 HTML 고유의 이벤트만 사용 가능합니다. 그러면, HTML 고유의 이벤트 말고 무엇이 있는가 하고 물으실텐데 SWAF에서는 사용자 이벤트를 정의할 수 있습니다. 이를 이용하여 개체간 메시징이 가능하게 되는 것입니다.
$listener는 핸들을 반환하는데, 이를 보관하고 있다 매핑을 제거할 때 사용합니다.
$listener.remove(handle)
위 메소드를 이용하면, element에 연결된 이벤트 핸들러를 제거할 수 있습니다.
$listener는 HTML이벤트를 별다른 기능 없이 빠르게 매핑할 때 사용합니다. 단순한 만큼 성능도 좋습니다.
[고도화된 이벤트 매핑]
SWAF에서는 좀 더 고도화된 메시징을 위해 $event 계열의 메소드를 제공합니다. 이들은 다음과 같습니다.
$event(source,map) - source개체의 이벤트 핸들러를 map에 따라 매핑합니다.
$event.remove(handle) - $event에 의해 정의된 매핑을 제거합니다.
$event.bypass(target,arguments) - 수신한 이벤트를 target 클래스로 전달합니다.
$event.fire(target,event_name,...) - target개체에 event를 발생시킵니다.
$event에서는 여러가지 매핑을 제공합니다.
1. 함수 매핑
함수 매핑은 개별 이벤트를 핸들러에 매핑하는 것으로, 샘플은 아래와 같습니다.
function onCliickBtn2(evt,src,type) {
alert(src.id+' '+type);
}
function onMouseProcessBtn2(evt,src,type) {
src.innerHTML=type;
}
$event($('btn2'),{
click : onClickBtn2,
mouseover : onMouseProcessBtn2,
mouseout : onMouseProcessBtn2
});
위 샘플은 btn2라는 id를 가지는 element로부터 click, mouseover, mouseout 이벤트에 대한 핸들러를 매핑하는 것입니다. element에서 해당 이벤트 발생시 각각의 함수가 호출됩니다.
2. 개체 매핑
핸들러 함수들을 나열하는 구조는 단위 페이지에서는 괜찮겠지만, 복잡도가 높아지거나 모듈화 되면 관리 및 유지보수에 어려움이 있습니다. 그래서 이들을 개체로 묶어 매핑할 수 있는 방법을 제공합니다. 샘플은 다음과 같습니다.
var objBtn3Listener={
onClick : function(evt,src,type) {
alert(src.id+' '+type);
},
onMouseover : function(evt,src,type) {
src.innerHTML=type;
},
onMouseout : function(evt,src,type) {
src.innerHTML=type;
}
}
$event($('btn3'),{
click : objBtn3Listener,
mouseover : objBtn3Listener,
mouseout : objBtn3Listener
});
위와 같이 objBtn3Listener라는 개체에 핸들러들을 정의하면, $event에서는 각 이벤트별로 해당 개체만 지정하면 개체 내의 핸들러와 자동으로 연결됩니다. 단, 개체의 핸들러는 onClick과 같이 on+이벤트 이름과 같은 형식이어야 합니다.
3. 클래스 매핑
SWAF에서는 OOP특징을 제공하는 클래스를 정의할 수 있습니다. 특히, 이들 클래스에 별도의 이벤트 핸들러 매핑을 정의할 수 있어 클래스간 메시징을 용의하게 할 수 있습니다.
이벤트 핸들러가 다음과 같은 클래스가 있다고 가정합시다.
$namespace('lib.classes');
$class({
class1 : {
/* namespace*/
NAMESPACE : lib.classes,
/* event handler mapping */
EVENT_MAP : {
click : 'onClick',
mouseover : 'onMouseOver',
mouseout : 'onMouseOut'
},
/* event handler */
onClick : function(evt,src,type) {
alert('click');
},
onMouseOver : function(evt,src,type) {
src.innerHTML="OVER";
},
onMouseOut : function(evt,src,type) {
src.innerHTML="OUT";
}
}
});
위와 같은 클래스 정의가 있을 때, 아래와 같이 인스턴스를 생성하면 이벤트와 연결할 수 있습니다.
var cls = new lib.classes.class1;
클래스의 이벤트 핸들러는 아래와 같이 원하는 이벤트만 개별적으로 매핑할 수 있습니다.
$event( $('btn4'),{
click : cls,
mouseover : cls,
mouseout : cls
});
위 샘플은 id가 btn4인 element로부터 발생하는 click, mouseover, mouseout 이벤트에 대한 핸들러를 각각 cls라는 클래스로 정의하는 것이며, 실제 이들 이벤트가 발생할 경우 cls의 이벤트 핸들러가 호출됩니다.
클래스의 이벤트 핸들러들 중 특정 핸들러만을 매핑할 때는 위와 같이 하지만, 클래스의 이벤트 핸들러가 모두 한 개체에 매핑된다면, 아래와 같이 간단히 정의할 수 있습니다.
$event( $('btn4'), cls );
위와 같이 할 경우, cls의 이벤트 매핑에 따라 btn4에서 발생하는 이벤트는 cls에 전달되어 핸들러가 호출됩니다.
한편, 클래스 정의에 EVENT_SRC : 'btn4' 와 같은 정의가 있다면, 이 클래스는 인스턴스 생성시에 이벤트 매핑이 해당 개체로 자동으로 연결됩니다.
[이벤트 핸들러 체인]
이벤트 매핑 정의시 map에는 여러 핸드러들을 중복 정의할 수 있습니다. 이 경우, 이들 핸들러들은 순서대로 체인이 구성되어 이벤트 발생시 차례대로 호출됩니다.
예를 들어,
$event($('btn7'),{
click : [ onClickBtn7, btn7Listener, cls ] // onClickBtn7 : function / btn7Listener : object / cls : class
});
위와 같이 정의할 경우, btn7이라는 id를 가지는 element로부터 click 이벤트가 발생시 onClickBtn7이라는 함수가 먼저 호출되고, btn7Listener개체에 정의된 onClick 함수가 호출되며, cls 클래스에 정의된 click 이벤트 핸들러가 호출됩니다.
HTML의 이벤트 핸들러가 그러하듯이 만약, 핸들러에서 false를 리턴한다면 이벤트는 다음으로 전달되지 않습니다. (브라우져로 전달되지도 않습니다.)
위와 같이 개별적인 이벤트에 대한 체인 구성 외에 개체의 이벤트 핸들러에 대한 체인을 아래와 같이 구성할 수 있습니다.
$event($('btn8'),[ cls1, cls2, {click : onClickBtn8} ]);
위와 같이 지정할 경우, cls1과 cls2에 지정된 이벤트 매핑과 click이벤트에 대한 onClickBtn8함수가 btn8에 매핑됩니다. 이 때, 중복되는 이벤트 핸들러가 있을 경우 위의 정의 순서대로 체인이 구성됩니다.
[사용자 정의 이벤트 및 클래스간 메시징]
SWAF에서는 사용자 이벤트를 정의하고, 이를 기존의 $event와 같은 메커니즘으로 활용할 수 있는 장점이 있습니다. 특히, 이를 이용하여 클래스간 메시징을 할 수 있는 특징이 있습니다.
사용자 정의 이벤트는 단순히 기존에 존재하는 자바스크립트 이벤트와 이름이 중복되지않게 매핑을 정의하기만 하면 됩니다.
$class({
class7 : {
NAMESPACE : lib.classes,
EVENT_MAP : {
myevent : 'onMyEvent'
},
onMyEvent : function(evt,src,type) {
alert('myevent fired');
}
}
});
var cls = new lib.classes.class7;
위의 클래스 정의는 'myevent'라는 사용자 이벤트가 정의되어 있으며, 이에 대한 핸들러로 onMyEvent가 정의되어 있습니다. 이 이벤트를 발생시키려면 다음과 같이 하면 됩니다.
$event.fire(cls, 'myevent')
특히, $event를 통해 element가 아닌 클래스나 개체에 매핑을 할경우 이에 대한 핸들러 체인을 구성할 수 있습니다.
$class({
class8 : {
NAMESPACE : lib.classes
}
});
var cls1 = new lib.classes.class8;
$event(cls1,[cls2, cls3]);
위와 같이 이벤트 매핑을 하면, cls1에서 발생하는 이벤트는 cls2를 거쳐 cls3로 전달됩니다. cls1은 HTML element가 아니므로 $event.fire를 통해 이벤트를 발생시킬 수 있습니다.
$event.fire(cls1, 'myevent')
사용자 정의 이벤트는 클래스 뿐 아니라 개체, HTML element 등 모든 자바스크립트 오브젝트에 매핑할 수 있습니다. $event.fire를 이용할 경우 추가로 사용자 정의 파라메터를 아래와 같이 전달할 수 있습니다.
$class({
class7 : {
NAMESPACE : lib.classes,
EVENT_MAP : {
myevent : 'onMyEvent'
},
onMyEvent : function(evt,src,type,arg1,arg2) {
alert('myevent fired');
}
}
});
var cls = new lib.classes.class7;
위에서 onMyEvent는 기본 파라메터 외에 arg1, arg2라는 추가 파라메터를 수신합니다. 이는 $event.fire에서 아래와 같이 전달할 수 있습니다.
$event.fire(cls, 'myevent','data1',2345);
이벤트 핸들러 내에서는 $event.bypass를 통해 다른 클래스에 이벤트를 전파하거나, $event.fire를 이용해 새로운 이벤트를 발생시킬 수 있습니다.
$event.fire는 HTML이벤트도 발생시킬 수 있는데, 이 경우 HTML Element 내에 inline으로 지정된 이벤트 핸들러 (예를 들면 <a id='xxx' onclick="processClick(this)"> 와 같이)도 호출 됩니다. 단, 이벤트는 브라우져로 전달되지 않습니다.
만약, 브라우져로 전달되는 이벤트를 발생시키기 위해서는 $listener.fire를 사용하면 됩니다.
이상으로 SWAF의 이벤트 지원에 대해 적어보긴 했는데, 클래스와 같이 이용할 경우 그 활용도가 상당하다고 생각합니다. 그러나, 아직 샘플 어플리케이션이 없는 상황에서 간단한 코드만으로 설명하기에는 한계가 있습니다.
위에서 설명한 이벤트 및 SWAF의 클래스에 대한 내용은 아래의 URL에서 함수 설명과 실제 동작을 확인해 볼 수 있습니다. 아직 다른 부분은 작성중입니다. 어서 빨리 문서화도 마무리짓고 여러 개발자들에게 소개하여 의견도 듣고, 영문화 작업을 하여 외국에 소개하고 싶은 마음이 굴뚝같습니다. 아직 갈 길이 멀지만, 장차 대표적인 국산 자바스크립트 프레임웍이 되기를 스스로 기원해 봅니다.
http://swaf.sourceforge.net
# by | 2007/11/15 15:27 | SWAF | 트랙백 | 덧글(0)




☞ 내 이글루에 이 글과 관련된 글 쓰기 (트랙백 보내기) [도움말]