イベントフェーズについて その1 では、3段階あるイベントフェーズの中で「ターゲット段階」・「バブリング段階」 をとりあげ、
イベントフェーズについて その2 では、残りのイベントフェーズ 「キャプチャ段階」をとりあげました。
今回は、イベントの伝播を止める方法について見ていきたいと思います。
早速 Adobe Flex3 API を調べてみると、イベントの伝播を停止する方法として次の2つのメソッドが用意されていることがわかります。
(今回のサンプルでは stopPropagation を使用しています)
----- APIに記載されている説明の引用 -----
stopImmediatePropagation()
イベントフローの現在のノードおよび後続するノードで、イベントリスナーが処理されないようにします。このメソッドはすぐに有効になり、現在のノードのイベントリスナーに影響します。これに対し、stopPropagation() メソッドは、現在のノードのイベントリスナーの処理がすべて終了するまで有効になりません。
stopPropagation()
イベントフローの現在のノードに後続するノードで、イベントリスナーが処理されないようにします。このメソッドは、現在のノード(currentTarget)のイベントリスナーには影響しません。 これに対し、stopImmediatePropagation() メソッドは、現在のノードとそれ以降のノードで、イベントリスナーが処理されないようにします。このメソッドを繰り返し呼び出しても影響はありません。このメソッドは、イベントフローの任意の段階で呼び出すことができます。
さっそくイベント伝播を停めるメソッドを使用したサンプルを見ていきましょう。
今回用意したサンプルは、予め用意されたBoxコンポーネント(生成時にマウスクリックのイベントリスナーをはっている)が8層の入れ子構造になっており、各Box上でマウスがクリックされるとイベントの伝播によってターゲットよりも外側のBoxのボーダライン色が青⇔赤に切り替わる様になっています。ただし、今回のポイントは一番外側のBoxに関してはイベント伝播の影響を受けず、自身のBoxがクリックされない限りボーダライン色は切り替わらない仕組みになっています。
実際に実行した際の初期画面はこんな感じです。
まずはBoxコンポーネント側のサンプルソースからみていきます。BoxコンポーネントのcreationCompleteイベントでマウスクリックイベントのリスナーを作成し、そのハンドラーでボーダーラインの色を切り替えています。
<?xml version="1.0" encoding="utf-8"?> <mx:Box xmlns:mx="http://www.adobe.com/2006/mxml" horizontalAlign="center" verticalAlign="middle" borderStyle="solid" borderColor="#0099FF" borderThickness="3" creationComplete="onCC()" > <mx:Script> <![CDATA[ private var _redBorder:Boolean = false; public function set redBorder(isRed:Boolean):void{ _redBorder = isRed; } private function onCC():void{ this.addEventListener(MouseEvent.CLICK, onClickHandler); } private function onClickHandler(e:MouseEvent):void{ this._redBorder = !_redBorder; if(_redBorder){ e.currentTarget.setStyle("borderColor", "#ff4400"); }else{ e.currentTarget.setStyle("borderColor", "#0099FF"); } } ]]> </mx:Script> </mx:Box>
次に実行ファイル側のサンプルソースを見ていきます。
layerBox0 ~ layerBox7までのBoxコンポーネントが入れ子構造になっており、application のcreationCompleteイベントで layerBox2 に対してマウスクリックイベントのリスナーを作成し、そのハンドラーで stopPropagation を実行しています。こうすることで イベントの伝播を layerBox2 で停止し、これ以上外側(layerBox1, layerBox0 )へ伝播しない様に設定しています。
<?xml version="1.0" encoding="utf-8"?> <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:Comp="Comp.*" layout="vertical" backgroundColor="#FFFFFF" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #FFFFFF]" horizontalAlign="center" verticalAlign="middle" creationComplete="onCC()"> <mx:Script> <![CDATA[ private function onCC():void{ layerBox2.addEventListener(MouseEvent.CLICK, onclickHandler); } private function onclickHandler(e:Event):void{ e.stopPropagation(); } ]]> </mx:Script> <Comp:Square id="layerBox0" width="400" height="300" > <Comp:Square id="layerBox1" width="360" height="270"> <Comp:Square id="layerBox2" width="320" height="240"> <Comp:Square id="layerBox3" width="280" height="210"> <Comp:Square id="layerBox4" width="240" height="180"> <Comp:Square id="layerBox5" width="200" height="150"> <Comp:Square id="layerBox6" width="160" height="120"> <Comp:Square id="layerBox7" width="120" height="90" /> </Comp:Square> </Comp:Square> </Comp:Square> </Comp:Square> </Comp:Square> </Comp:Square> </Comp:Square> </Comp:Square> </mx:Application>
例えば、一番内側のlayerBox7をクリックした際の結果は以下のようになります。
一番外側のBox枠線だけ色が変わらず、残りの枠線は赤色に切り替わりました。
イベントフェーズの順番に処理を追っていくと・・・・
1. 「キャプチャ段階」 では イベントリスナーを設定していない為、何も処理は行われない
2. 「ターゲット段階」で クリックされた layerBox7 の枠線の色を赤色にセットします
3. 「バブリング段階」で layerBox6 から外側に向かって順に枠線の色を赤色にセットします
4. layerBox2 までバブリングしてきた後、layerBox2 で stopPropagation() が実行されます
5. stopPropagation() の実行により、伝播は中止されlayerBox1及びlayerBox0 では枠線の色が変わらない
という流れになります。
ちなみにですが、stopPropagation() はイベントの伝播を停めるメソッドですので、layerBox0 をクリックしたときには 「ターゲット段階」の処理として layerBox0 の枠線の色は赤色に切り替わります。この場合は、イベントフェーズ対象に layerBox2 が登場しないのであたりまえといえばあたりまえですね。 (私はサンプル作成中に少しだけ混乱しました。ほんの少しだけ)
全3回に渡ってイベントフェーズとイベント伝播の停止を見てきました。サンプルソースが単純なので、その便利さがいまいち伝わらなかったかもしれませんが、イベント送信 + イベント伝播 + イベント停止 の使い方を覚えると画面の作り込みが楽しくなってきます。 是非応用して楽しい画面をつくってみてください。