Ext JSやRapid Driveなど
システム開発の技術情報をご紹介。

お問い合わせ 資料請求 無料見積り

お電話でお気軽にお問い合わせくださいTel 03-6805-2904 営業時間 [平日]AM 9:30 - PM 6:30

イベント処理

イベント処理について

イベントデリゲート

例えば、DOMノードのイベント操作をする場合、1つのHTMLエレメントに対して1つのイベントリスナーを登録していくことはおすすめできません。アプリケーションの規模によってはイベントの登録がとても多くなります。これによって、ソースコードも膨大な量となり、またイベントの管理も煩雑になるため、イベントリスナー登録は少なくするべきでしょう。

次のようなHTMLエレメントの構造があります。

<div id="colors">
    <div id="red" class="primary">Red</div>
    <div id="green" class="secondary">Green</div>
    <div id="blue" class="primary">Blue</div>
</div>

IDが「red」、「green」、「blue」のDIVタグをクリックしたときのイベントリスナーを登録する場合、まず、それぞれのタグ(3つ)に対してイベントリスナーを登録することを思いつくでしょう。

実際に登録すると、下記のような書き方になります。

Ext.fly( 'red' ).on( 'click', function(){
    /*...*/
});
Ext.fly( 'green' ).on( 'click', function(){
    /*...*/
});
Ext.fly( 'blue' ).on( 'click', function(){
    /*...*/
});

つまり、これらの処理は次の図のような形になります。

イベントデリゲート

しかし、先ほどのことから、イベントリスナー登録は可能であるなら減らすべきでしょう。この場合、red,green,blueのコンテナとなるエレメントに「colors」というIDを持つDIVタグが存在します。今回はこのタグを利用してイベントリスナーを登録してみましょう。

Ext.fly( 'colors' ).on( 'click', function( e, target ) {
    alert( target.innerHTML + 'が選択されました!' );
    var target = e.getTarget( '.primary' );
    if( target ) {
        // 「.primary」クラスのみ処理
        alert( 'このタグはCSSクラス:primaryが指定されています!' );
    }
});

'click'はDOMイベントなので、メソッドシグネチャはeとtargetです。

イベントとしては、ID「colors」のDIVタグがクリックされたときのイベントを記述することになりますが、targetは実際にクリックされたDOMオブジェクトが引き渡されてくるので、このDOMオブジェクトを利用して、処理を分岐させます。

さらに、イベントオブジェクトであるeのgetTargetメソッドを利用して、ターゲットを絞り込むことができます。サンプルコードでは、CSSクラス「.primary」をCSSセレクタとして使用し、ターゲットを取得しています。

これをイベントのデリゲート(委譲)といいます。コンテナエレメントのイベントによるハンドラ内で処理を分岐させることで、イベントリスナー登録をまとめることができます。

イベントバブリング

イベントデリゲートで使用したサンプルコードでは、コンテナエレメントのイベントのみをイベントリスナー登録しましたが、さらにコンテナエレメントに含まれるエレメントのイベントリスナー登録も同時に行った場合、どのような順番でイベントが発生するのでしょうか?

次の図は、「red」をクリックしたときのclickイベントの発生順です。

イベントバブリング

先にコンテナ内のエレメント「red」のclickイベントハンドラが実行され、その後にコンテナエレメント「colors」のイベントハンドラが実行されます。このように、ネストしたHTMLのイベントは、内側から外側に向かって順にイベントが発生していきます。図のように下から上に上がっていくイメージから(泡が上っていく様子)からバブリング、またはイベントバブリングと呼ばれます。

リスナー登録時の引数

イベントリスナーを登録する際、引数によってさらに高度なイベント処理をすることが可能です。第4引数のオブジェクトに以下の項目を設定します。

scope:Object
検証中
delegate:String
ターゲットをフィルターにかける、もしくはターゲットの子孫を探すためのCSSセレクタを設定します。
Panel.on( ' enable', function( e, t ) {
    // コールバック内容
}, this, {
    // fooクラスに絞り込む
    delegate: '.foo'
});
stopEvent:Boolean
trueに設定した場合、イベントを停止します。preventDefaultとstopPropagationをtrueに設定した場合と同様です。
preventDefault:Boolean
trueに設定した場合、ブラウザ標準のイベントハンドリングを防ぎます。
stopPropagation:Boolean
trueに設定した場合、イベントのバブリングを止めます。
normalized:Boolean
trueに設定した場合、ハンドル関数の引数にExt.EventObjectではなくブラウザイベントを渡します。
target:Ext.Element
検証中
delay:Numbe
ハンドラの実行を遅らせます(ミリ秒)。イベントが発生してから設定時間経過後にハンドラが実行されます。
single:Boolean
trueに設定した場合、ハンドラ関数は1度しか実行されません。
buffer:Number
Ext.util.DelayedTaskに動作の予約をして、ハンドラの実行を遅らせます(ミリ秒)。もし、遅延中に再びイベントが発生した場合、実行待ちのハンドラをキャンセルし、このイベントによるハンドラを予約します。

イベントのリレー

Ext.util.ObservableクラスのrelayEventsメソッドを使用すると、別のコンポーネントで発生したイベントを、あたかもそのコンポーネントで発生したイベントのように扱うことができます。これをイベントのリレーといいます。

以下に、その使用例を記述します。relayEventsメソッドの第1引数にイベントが発生するコンポーネントを、第2引数はリレーするイベントの名前を配列にして設定します。

// 'win'で発生したshowイベントとhideイベントをPanelにリレーする
Panel.relayEvents( win, [ 'show', 'hide' ] );
// リレーされるPanelに対してイベントリスナー登録をする
Panel.on( 'show', function( w ) {
    console.log( arguments );
}, this );

この場合、winコンポーネントで発生した「show」イベントと「hide」イベントが、Panelコンポーネントで発生したイベントのように使用できます。

上記のようにイベントによって渡される引数をconsole.logを使用して確認すると、winコンポーネントで発生したイベントであることがわかります。しかし、イベントリスナーを登録したコンポーネントはPanelであることから、イベントがリレーされたことを確認できると思います。