イベントを使う
Ext JS のコンポーネントとクラスは、ライフサイクル中に様々な時点で幅広いイベントを発火します。イベントによって、アプリケーションでの変化に対して、コードが反応できるようになります。Ext JS の重要な概念の一つです。
イベントとは?
イベントは、クラスに何かが起きると発火するものです。例えば、
Ext.Component
が画面に描画されると、Ext JS はレンダリングが完了した後にイベントを発火します。シンプルな listeners
オブジェクトを構成すれば、そのイベントをリッスンする事ができます。
Ext.create('Ext.Panel', { html: 'My Panel', renderTo: Ext.getBody(), listeners: { afterrender: function() { Ext.Msg.alert('We have been rendered'); } } }); |
このサンプルで、Preview ボタンをクリック (注1) すると、パネルが画面に描画され、次に定義したアラートメッセージが表示されます。 あるクラスが発火する全てのイベントは、そのクラスのAPIページに一覧があります。例えば、 Ext.panel.Panel には 現在 45のイベントがあります。
- 注1: ライブプレビューは次のページで実行できます。
Ext JS Guides | Events in Ext JS 5
イベントをリッスンする
Ext.Component の afterrender イベント は便利ですが、もっと頻繁に使うことになるイベントがあります。例えば、 Ext.button.Button はクリックされたときに、 click イベントを発火します:
Ext.create('Ext.Button', { text: 'Click Me', renderTo: Ext.getBody(), listeners: { click: function() { Ext.Msg.alert('I was clicked!'); } } }); |
あるコンポーネントには、必要とするイベントリスナーを持っています。次のサンプルでは、mouseover
のリスナー内に this.hide()
を呼び出して、Button を非表示にしています。
次にその 1秒後にボタンを再び表示します。this.hide()
が呼び出されると、Button は非表示になり、hide
イベントが発火します。hide
イベントは hide
リスナーを呼び出し、それの中で 1秒待機した後に Button を再び表示しています。
Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'My Button', listeners: { mouseover: function() { this.hide(); }, hide: function() { // Waits 1 second (1000ms), then shows the button again Ext.defer(function() { this.show(); }, 1000, this); } } }); |
イベントリスナーは、イベントが発火される度に呼び出されるため、何度でもボタンの表示と非表示を繰り返す事ができます。
後でリスナーを追加する
前のサンプルでは、クラスをインスタンス化する時に、コンポーネントにリスナーを渡しました。しかし、もし、既にインスタンスがある場合、on
関数を利用してリスナーを追加する事ができます。
var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'My Button' }); button.on('click', function() { Ext.Msg.alert('Event listener attached by .on'); }); |
リスナーのコンフィグを使った時と同じように、.on
メソッドを使うときも、複数のリスナーを指定することもできます。次は、mouseover
イベントでボタンの表示をセットする前のサンプルを再現します。
var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'My Button' }); button.on({ mouseover: function() { this.hide(); }, hide: function() { Ext.defer(function() { this.show(); }, 1000, this); } }); |
リスナーを取り外す
いつでもリスナーを追加できるのと同様に、取り外す事もできます。その場合は un
関数を利用します。リスナーを取り外すには、関数を参照をする必要があります。以前のサンプルでは、リスナーのオブジェクト、または on
の呼び出しに関数を渡しました。今回は、関数を事前に生成し、そのカスタム関数を doSomething
という変数に代入します。その doSomething
関数を listeners
オブジェクトに渡しています。
最後の所で
Ext.defer
関数が追加されているので、最初の 3秒間のうちにボタンをクリックするとアラートが表示されますが、3秒を経過した後ではリスナーが取り外されるため、何も起こりません。
var doSomething = function() { Ext.Msg.alert('listener called'); }; var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'My Button', listeners: { click: doSomething, } }); Ext.defer(function() { button.un('click', doSomething); }, 3000); |
リスナーの scope オプション
scope
は、ハンドラー関数内での this
の値を設定します。デフォルトでは、これはイベントを発火したクラスのインスタンスが設定されます。通常はこれが求められる機能性ですが、常にそうだというわけではありません。この機能性により、このガイド 2つ前のサンプルで ボタンを非表示にするときに、this.hide()
メソッドを呼び出す事ができます。次のサンプルでは、Button と Panel を生成します。その後、ハンドラーのスコープが Panel 動作するように、ボタンの click イベントをリッスンします。
そうするためには、ハンドラー関数の代わりにオブジェクトを渡す必要があります。そのオブジェクトには、関数とスコープが含まれています。
var panel = Ext.create('Ext.Panel', { html: 'Panel HTML' }); var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'Click Me' }); button.on({ click: { scope: panel, fn: function() { Ext.Msg.alert(this.getXType()); } } }); |
このサンプルを実行すると、click ハンドラーの this
の値は Panel の参照になります。それがわかるように、スコープされたコンポーネントの xtype
をアラートします。ボタンがクリックされると、パネルの xtype
がアラートされるのが見えます。
イベントを 1回だけリッスンする
あるイベントを 1回だけリッスンしたい場合もあるかもしれません。イベントそのものは、何回も発火するかもしれないけれど、1回だけリッスンしたいだけという場合です。次のコードがこの状況を表します。( single
オプションに注目)
var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'Click Me', listeners: { click: { single: true, fn: function() { Ext.Msg.alert('I will say this only once'); } } } }); |
buffer コンフィグを利用する
短い間に何回も発火するイベントに対して、buffer
コンフィグを使うと、リスナーが呼び出される回数を減らす事ができます。この場合、何回クリックしても、ボタンの click リスナーは 2秒に一回だけ呼び出されます。
var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: 'Click Me', listeners: { click: { buffer: 200, fn: function() { Ext.Msg.alert('I say this only once every 2 seconds'); } } } }); |
カスタムイベントの発火
自分で定義したイベントを発火させるには fireEvent
にイベント名を渡して呼び出します。次のサンプルでは、2つの引数 (ボタン自身と、1〜100の間のランダムな数値) を渡す myEvent
というイベントを発火します。
var button = Ext.create('Ext.Button', { renderTo: Ext.getBody(), text: "Just wait 2 seconds", listeners: { myEvent: function(button, points) { Ext.Msg.alert('myEvent fired! You score ' + points + ' points'); } } }); Ext.defer(function() { var number = Math.ceil(Math.random() * 100); button.fireEvent('myEvent', button, number); }, 2000); |
ここでも Ext.defer
を使って、2秒でカスタムイベントを発火する関数の実行を遅らせています。イベントが発火すると、myEvent リスナーがイベント拾って、渡された引数を表示します。
DOMイベントをリッスンする
全ての Ext JS コンポーネントは、全てのイベントを発火するわけではありません。しかし、コンテナのエレメントをターゲットにすると、コンポーネントがリッスンできる様々なネイティブなイベントにアタッチする事ができます。このサンプルでは、 Ext.container.Container. をターゲットにしています。コンテナには click イベントはありません。さて、一つ追加しましょう。
var container = Ext.create('Ext.Container', { renderTo: Ext.getBody(), html: 'Click Me!', listeners: { click: function(){ // 下記のコードがないと発火しません Ext.Msg.alert('I have been clicked!'); } } }); container.getEl().on('click', function(){ this.fireEvent('click', container); }, container); |
2つ目のブロックのコードがなかったら、コンテナの click リスナーは発火しません。コンテナのエレメントをターゲットとし、click リスナーをアタッチして、コンテナのイベント機能を拡張しました。
イベント正規化
イベント正規化があるから Ext JS 5 のアプリケーションは、タッチパネル デバイス上で動作できます。この正規化は、裏で動作し、標準のマウスイベントを対応するタッチとポインターイベントに変換します。
ポインターイベントは、w3c 標準で、入力デバイス(マウス、タッチ、スタイラスなど)に関わらず、画面の特定の座標をターゲットするイベントを扱います。
あなたのコードがマウスイベントのリスナーをリクエストすると、フレームワークが必要に応じてよく似たタッチやポインターイベントを追加します。例えば、アプリケーションが mousedown
リスナーをアタッチするには、次の様にします。
myElement.on('mousedown', someFunction); |
タッチイベントをサポートするデバイスの場合には、イベントシステムがこれを touchstart
に変換します。
myElement.on('touchstart', someFunction); |
または、ポインターイベントをサポートするデバイスの場合には、これを pointerdown
に変換します。
myElement.on('pointerdown', someFunction); |
この変換は既に準備されているので、コードを追加しなくても、タブレットやタッチパネルのサポートを実現する事ができます。
ほとんどの場合には、フレームワークがマウス、タッチ、ポインターの入力の間をシームレスで切り替える事ができます。しかし、いくつかのマウス操作(例えば、mouseover
)は簡単にタッチ操作に変換できません。このようなイベントは一つひとつ取り組む必要があり、次のセクションで説明します。
ジェスチャー
通常の DOM イベントに加え、エレメントは合成された “ジェスチャー” イベントも発火します。Sencha Touch のイベントシステムは、Ext JS 5 の新しいイベントシステムの基盤となっていますから、Sencha Touch のユーザーは、既にこの概念をご存じのことでしょう。
ブラウザの視点からすると、ポインター、タッチ、マウス、の各イベントには、主に3つのタイプ (Start, Move, End) があります。
Event | Touch | Pointer | Mouse |
---|---|---|---|
Start | touchstart | pointerdown | mousedown |
Move | touchmove | pointermove | mousemove |
Stop | touchend | pointerup |
このイベントのシーケンスとタイミングを解釈した後、drag
、 swipe
、 longpress
、 pinch
、 rotate
、 tap
などの複雑なイベントを合成します。Ext JS アプリケーションは、他のイベントと同じように、ジェスチャーイベントをリッスンする事ができます。例えば。
Ext.get('myElement').on('longpress', handlerFunction); |
オリジナルの Sencha Touch ジェスチャーシステムは、主にタッチ イベントの為に設計されました。ジェスチャー システムにポインターとマウス イベントのサポートを追加すると、Ext JS 5 がどの入力でもジェスチャーに反応するような仕組みが可能になりました。このため、全てのジェスチャーは、タッチ入力でトリガーされるだけではなく、全てのシングル ポイントのジェスチャー(タップ、スワイプなど)もマウスを利用し、トリガーする事も可能になりました。その結果、入力方法に関わらず、複数デバイスに渡ってシームレスはジェスチャーシステムができました。