나만의 이벤트 디스패쳐
천둥상어
·2024. 1. 17. 23:00
이벤트를 전달하는 방법은 몇 가지가 있다.
개인적으로는 이벤트를 순차적으로 내리고 올리는(버블링, 캡춰링) 방법을 선호한다.
이 방식은 많은 절차를 타고 가야 하는 단점이 있다.
예를 들어 C 클래스의 이벤트를 D 클래스에 전달하고 싶다면
C클래스에서 B 클래스로 버블링하고
B 클래스에서 다시 D 클래스로 캡춰링 해줘야 한다.
그럼에도 내가 좋아하는 이유는
이벤트 추적이 쉽고 버블링, 캡춰링시
추가적인 정보 가공이 용이하기 때문이다.
사실 이러한 방법은 언어에서 기본적으로 제공되거나
프레임 워크나 라이브러리의 경우 자신만의 문법으로 구현 되어 있다.
그럼에도 내가 커스텀 디스패쳐를 구현하고 싶은 이유는
공통된 방법으로 사용하고 싶기 때문이다.
구조는 내가 가장 많이 UI 개발을 한 ScaleForm의 구조를 참고 했다.
이벤트명, 콜백함수명, 스코프를 넘겨서 해당 이벤트를 등록하고,
디스패치가 일어나면 콜백함수를 호출한다.
함수 자체가 아닌 함수명을 넘기는 이유는
콜백 함수의 블록 스코프를 이벤트를 걸어주고 있는
스코프로 잡아주기 위함도 있지만
가장 큰 이유는 dispatchEvent 함수를 호출하여
별도의 콜백 함수 없이 버블링을 하기 위해서다.
UIComponent.js ( Core 클래스 )
export default class UIComponent {
constructor() {
this.listener = {};
}
// 이벤트 등록
addEventListener($eventType, $callBack, $scope) {
if( this.listener[$eventType] == undefined ){
this.listener[$eventType] = {};
}
const fnc = $scope[$callBack].bind($scope);
this.listener[$eventType] = {};
this.listener[$eventType].param = {type:$eventType, target:this };
this.listener[$eventType].callback = fnc;
}
// 이벤트 삭제
removeEventListener($eventType) {
if( this.listener[$eventType]) {
delete this.listener[$eventType];
}
}
// 이벤트 디스패쳐
dispatchEvent($e) {
if( this.listener[$e.type] != undefined ) {
const param = this.listener[$e.type].param;
// 버블링 과정에서 추가된 속성이 있다면 포함시킨다.
for( let property in $e) {
if (param[property] == undefined) param[property] = $e[property];
}
this.listener[$e.type].callback(param);
}
}
}
Button.js
import UIComponent from "./UIComponent";
export default class Button extends UIComponent {
constructor() {
super();
}
// 원래는 클릭이나 오버, 아웃 같은 액션시 발생시켜야 함.
// 테스트를 위해서 강제로 디스패쳐를 발생 시키는 함수
testDispatchEvent() {
this.dispatchEvent({type:'EvtTest', x:10, y:20});
}
}
container.js
import Button from './Button';
import UIComponent from "./UIComponent";
export default class Container extends UIComponent {
constructor() {
super();
// btn0은 전용 콜백 없이 버블링
this.btn0 = new Button();
this.btn0.addEventListener('EvtTest', 'dispatchEvent', this);
// btn1은 전용 콜백을 거쳐서 버블링 및 속성 추가
this.btn1 = new Button();
this.btn1.addEventListener('EvtTest', 'addProperty', this);
}
addProperty($e) {
$e.addX = 10;
this.dispatchEvent($e);
}
}
Main.js
import Container from "./ui/Container";
class Main {
constructor() {
this.container = new Container();
this.container.addEventListener('EvtTest', 'testFnc', this);
this.container.btn0.testDispatchEvent();
this.container.btn1.testDispatchEvent();
// 이벤트 삭제
this.container.removeEventListener('EvtTest');
this.container.btn1.testDispatchEvent();
this.container.btn1.testDispatchEvent();
}
testFnc($e) {
console.log($e);
}
}
const main = new Main();
Result
'프로그래밍 > 개발 일기' 카테고리의 다른 글
로컬 서버에서 스파인 플레이어 실행하기 (0) | 2024.08.22 |
---|---|
[서적 구입] 개발자가 영어도 잘해야 하나요? (0) | 2024.07.06 |
[에러] opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ] (0) | 2024.04.02 |
애증의 Pixi.js (0) | 2024.03.12 |
한 두수 앞을 보고 개발 할 수는 없을까? (0) | 2023.12.28 |