kagamihogeの日記

kagamihogeの日記です。

イベントのバブリングの基礎学習

Flex のイベントにはバブリングという概念がある。これを使うことで子から親コンポーネントへとイベントの発生を伝播させることができる。

というわけで実験のために下記のようなコードを実行してみる。

<?xml version="1.0" encoding="utf-8"?>
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" initialize="init()">
    <mx:Script>
        <![CDATA[
            private function init():void {
                v1.addEventListener("customEvent", handler1);
                v2.addEventListener("customEvent", handler2);
                v2.addEventListener("customEvent", handler2_1);
                v3.addEventListener("customEvent", handler3);
                v4.addEventListener("customEvent", handler4);
            }
            private function handler1(event:Event):void {
                trace("ccc1");
            }
            private function handler2(event:Event):void {
                trace("ccc2");
            }
            private function handler2_1(event:Event):void {
                trace("ccc2_1");
            }
            private function handler3(event:Event):void {
                trace("ccc3");
            }
            private function handler4(event:Event):void {
                trace("ccc4");
            }
            private function c():void {
                v4.dispatchEvent(new Event("customEvent", true));
            }
        ]]>
    </mx:Script>
    <mx:VBox id="v1" width="100%" height="100%">
        <mx:VBox id="v2" width="100%" height="100%">
            <mx:VBox id="v3" width="100%" height="100%">
                <mx:VBox id="v4" width="100%" height="100%">
                    <mx:Button click="c()" />
                </mx:VBox>
            </mx:VBox>
        </mx:VBox>
    </mx:VBox>
</mx:VBox>

これを実行して、VBox の入れ子のいちばん奥に設置したボタンを押すと、下記のような実行結果が得られる。


ccc4
ccc3
ccc2
ccc2_1
ccc1

子の VBox から順に親の VBox へとイベントが伝播し、各コンポーネントに登録したイベントハンドラが動いている。

ポイントは dispatchEvent に渡す Event のコンストラクタの第二引数を true にしている点。この引数は、子から親コンポーネントへイベントの発火を伝播―バブリング―を行うかどうかを決定する。デフォルトは false なので、自前のイベントを送出するときにバブリング段階を処理させたい場合は true にする必要がある。よって上のソース例の場合、new Event("customEvent", true) を new Event("customEvent") にすると、バブリングは行われないため、実行結果は ccc4 と表示される。

イベントの伝播を途中で止めたい場合は、Event クラスの stopImmediatePropagation か stopPropagation を呼ぶ。両者の違いは、前者は stopImmediatePropagation を呼んだイベントハンドラ以降のイベントハンドラは実行されなくなり、後者は stopPropagation を呼んだイベントハンドラの登録されているコンポーネントは引き続き処理対象だが、それ以降のイベントハンドラは実行されなくなる。つまりはメソッド名が示すとおりで、即座に止めるか現在のコンポーネントでは続行するか、の違いである。
でまぁ、実験。

private function handler2(event:Event):void {
    trace("ccc2");
    event.stopPropagation();
}

こうすると実行結果は下記のようになる。


ccc4
ccc3
ccc2
ccc2_1

id="v2" のコンポーネントに登録されてるイベントハンドラまで実行されてる様子が分かります。

private function handler2(event:Event):void {
    trace("ccc2");
    event.stopPropagation();
}

一方、stopPropagation を stopImmediatePropagation にするとどうなるか。

private function handler2(event:Event):void {
    trace("ccc2");
    event.stopImmediatePropagation();
}

実行結果はこうなる。


ccc4
ccc3
ccc2

id="v2" のコンポーネントに登録されてる handler2 まででイベントの伝播が止まっているのが分かる。

この仕組みを使うことでカスタムコンポーネント間の連携をやれるっぽいですね。