2-2. CustomEvent
clickやsubmitといったDOMのイベントの他にあるアプリケーションレベルのイベントです。
私は自分で実装していますが、各種Jsライブラリで賄うことも出来ます。実装例
app.addEvents = function(){
var args = $.makeArray(arguments);
for (var i = 0, max_i = args.length; i < max_i; i++) {
app.events[args[i]] = [];
}
}
app.addListener = function(name, fh, context){
if (!(name in app.events)) {
console.log('unknown event ' + name);
}
app.events[name].push([fh, context]);
}
app.fireEvent = function(){
var args = $.makeArray(arguments);
var name = args.shift();
if (!(name in app.events)) {
console.log('unknown event ' + name);
return;
}
for (var i = 0, max_i = app.events[name].length; i < max_i; i++) {
app.events[name][i][0].apply(app.events[name][i][1] || app, args);
}
}
効果
この機構はアプリケーション内で発生するイベントを視覚化、イベント処理を抽象化し、イベントの発生元と影響先間の結合を弱くしDOM構造の変更つまり画面レイアウトの変更に強くします。
7kai Tasksではイベントを駆使し、PC版とスマホ版の仕様・コードをなるべく共通化しています。
メソッド
- app.addEvents(name) ... イベント定義(こういうイベントがあります)
- app.addListener(name, function) ... イベント処理定義(このイベントが発火したらこのfunctionをcall)
- app.fireEvent(name, args) ... イベント発火(このイベントを発火)
イベント定義: app.addEvents(name)
- スコープ: 最外層かつ上部
そのアプリにどんなイベントがあるのか分かりやすくする為、上部に固めて宣言します。
宣言する前のイベントに対して app.addListener や app.fireEvent は出来ません。
Code
app.addEvents('setup'); // application setup
app.addEvents('clear'); // memory and dom clear
app.addEvents('reload'); // clear => setup
app.addEvents('resize'); // window resize
app.addEvents('alert'); // trouble
app.addEvents('selectTab'); // tag component
app.addEvents('receiveSign'); // receive sign from api (signin)
app.addEvents('receiveToken'); // receive token from api (online)
イベント処理定義: app.addListener(name, function)
- スコープ: 最外層, app.setup.*
Code
// アプリケーションにリストが登録された場合、メモリに格納
app.addListener('registerList', function(list){
app.data.list_map[list.id] = list;
});
// リストが選択された場合、DOM書き換え
// `data-setup="listname"` と初期化処理が指定されているDOM全てのtextが書き換わる
app.setup.listname = function(ele){
app.addListener('openList', function(list){
ele.text(list.name);
});
}
イベント発火: app.fireEvent(name)
- スコープ: どこでも
「リストを開く」というイベントの場合
- メニューからクリック
- 画面初期化時に前回開いていたリストをlocalStorageから取得
- デスクトップ通知をクリック
- ショートカットキー操作
という4通りの発火元がありますが、リストを開いた処理については発火元周辺のコードで一切関知しない為、大変書き易いです。
Code
// リストのメニューをクリックしたら対応するリストを開くイベントを発火
app.setup.listMenu = function(li){
var id = li.data('id');
var list = app.data.list_map[id];
app.fireEvent('openList', list);
};
// リストが開かれたらタスクの表示条件を更新
app.addListener('openList', function(list){
app.fireEvent('filterTask', { list_id: list.id });
});