イベント
概要
BitsmistJSの特徴のひとつが、イベントドリブンです。各コンポーネントでは様々なタイミングでイベントが発生します。イベントが発生すると、BitmistJSが引数を準備し、登録されているイベントハンドラを呼び出します。各イベントに対するイベントハンドラ内に処理を記述することで、コンポーネントの動作を作成していきます。ここではイベントについて説明します。
イベントはイベントオーガナイザによって処理されます。
イベントの種類
発生するイベントには、“click”イベントのようなJavascriptネイティブのイベントと、“doSetup”のようなBitsmistJSの独自のイベントがあります。
独自イベントはJavascript標準のカスタムイベントを使って実装されています。そのため多くの場合、JavascriptネイティブなのかBitmistJSオリジナルなのか、を意識せずに使えるようになっています。
BitsmistJSオリジナルイベント
ここではComponentコンポーネントが発生させるイベントの一覧を紹介します。BitsmistJSイベントは1つのイベントに対し、基本的にbefore/do/afterで始まるイベントの3セットになっています(そうでないものもあります)。doで始まるイベントでメインとなる処理を行い、before/afterで始まるイベントでは、その前処理/後処理を行います。
イベント | 説明 |
---|---|
beforeStart | 初期化時の処理を行います。 |
afterStart | |
beforeStop | 終了時の処理を行います。 |
doStop | |
afterStop | |
beforeSetup | コンポーネントに設定を反映する処理を行います。 |
doSetup | |
afterSetup | |
afterAppend | HTMLテンプレートが追加された後の処理を行います。 |
beforeRefresh | 画面描画時の処理を行います。 |
doRefresh | |
afterRefresh | |
doTarget | 取得するデータを決定する処理を行います。 |
beforeFetch | データ取得時の処理を行います。 |
doFetch | |
afterFetch |
イベントハンドラの書き方
各イベントハンドラは共通の引数を持っています。Javascriptネイティブなイベント、BitsmistJSオリジナルなイベント、いずれもこのイベントハンドラの形式で対応します。
onDoSetup(sender, e, ex) { }
イベントハンドラには3つの引数があります。この3つの引数はBitsmistJSによってセットされます。
sender
senderにはこのイベントを発生させたオブジェクトが渡されます。例えば、クリックイベントの場合はクリックした要素、doSetup()の場合はコンポーネント自身が入っています。
e
Javascriptネイティブなイベントの場合、ここにはイベントリスナーに渡されるイベント情報がそのまま渡されます。例えばclickイベントの場合は、MouseEventオブジェクトが渡されます。BitmistJSオリジナルなイベントの場合は、イベントを発生させたコンポーネントが渡すイベント情報が入ります。
ex
この引数は設定のイベントハンドラ情報の“options”で指定された内容が渡されます。
イベントハンドラ情報はイベント設定で“eventName”の値としてセットされるオブジェクトです。
イベントハンドラの指定方法
どの要素のどのイベント時にどのイベントハンドラを使用するかを、設定の“events”セクションに記述します。
_getSettings() { return { "settings": { "name": "BarMain", }, "events": { "this": { "handlers": { "doSetup": this.onDoSetup } }, "btn-menu": { "handlers": { "click": this.onBtnMenu_Click } } } } }
この例では“this”(コンポーネント自身、この場合はBarMain)のdoSetupイベントでonDoSetup()メソッドを呼び出すように指定しています。またメニューボタンがクリックされた際には、onBtnMenu_Click()メソッドを呼び出すようにも指定しています。
要素の指定の仕方、ハンドラの指定の仕方など、詳細はイベントオーガナイザのリファレンスをご覧ください。
イベントハンドラの順番
同じ要素の同じイベントに複数のイベントハンドラがある場合、基本的には登録された順番に実行されます。
_getSettings() { return { "settings": { "name": "BarHeader", }, "events": { "this": { "handlers": { "doSetup": [ { "handler": this.onDoSetup1 }, { "handler": this.onDoSetup2, } ] } } } } }
上記の場合、this.onDoSetup1()→this.onDoSetup2()の順に実行されます。
ハンドラ情報の“order”に数値を指定すると、この順番を制御することができます。より高い数値のイベントハンドラが先に実行されます。指定がない場合は0となります。
_getSettings() { return { "settings": { "name": "BarHeader", }, "events": { "this": { "handlers": { "doSetup": [ { "handler": this.onDoSetup1 }, { "handler": this.onDoSetup2, "order": 10 } ] } } } } }
上記の場合は、this.onDoSetup2()→this.onDoSetup1()の順になります。
イベントハンドラの実行を同期する
各イベントハンドラは非同期で実行されます。Promiseを返し適切なタイミングでresolve/rejectすることで、次の処理はこのイベントハンドラの終了を“待つ”ようになります。
onDoSetup1(sender, e, ex) { return new Promise((resolve, reject) => { setTimeout(() => { console.log("setup1"); resolve(); }, 2000); }); } onDoSetup2(sender, e, ex) { console.log("setup2"); }
上記の2つのイベントハンドラがコンポーネントのdoSetupイベントに登録されていた場合、
setup1 setup2
と順番に表示されます。もしPromiseを返さない場合はどうなるでしょうか?
onDoSetup1(sender, e, ex) { setTimeout(() => { console.log("setup1"); }, 2000); } onDoSetup2(sender, e, ex) { console.log("setup2"); }
setup2 setup1
setup2が先に表示されます。
これは同じイベントに複数のイベントハンドラが存在する場合の例でしたが、違うイベントが続けて発生する場合も同じことが言えます。例えばコンポーネントのsetup()メソッドを呼び出すと、beforeSetup→doSetup→afterSetupという流れでイベントが発生しますが、beforeSetupのイベントハンドラでPromiseを返さない場合は、beforeSetupの処理の終了を待たずに、doSetupの処理が走ります。後続の処理が待つ必要がある場合は、常にPromiseを返してください。