25

予想/疑似例:

stage.addEventListener(MouseEvent.CLICK, onClick.someWayToPassParameters(true, 123, 4.56, "string"));
function onClick(e:MouseEvent):void {
    trace("Received " + someWayToRetrieveParameters().b/i/n/s + ".");
}

何年もの間 (3~4 年)、すべての Web サイト、フォーラム、ブログ、どこを検索しても、これを行う簡単な方法はないと言われてきました。彼らは通常、次のことを提案します。

  • リスナーを動的オブジェクトに追加します。値を追加のプロパティに設定し、関数で参照できます (e.target.property / e.currentTarget.property)。

    すべてのクラスが動的であるとは限りません。たとえば、スプライトでは機能しません。

  • オブジェクトのクラスをカスタム クラスで拡張して、プロパティを追加するか、単に動的にします。

    毎回まったく新しい微調整クラスを作成する必要があります。

  • イベント ハンドラーとして無名関数を使用します。

    参照はありません(そしてそれは醜いです)。リスナーを削除してリソースを解放するには、arguments.callee を使用して関数自体の内部から行う必要があります。

  • パラメーターを使用して、イベント ハンドラー内で別の関数を呼び出します。

    そして、イベント ハンドラー呼び出しのどこにパラメーターが移動しますか?

  • イベント ハンドラーをパラメーターと同じスコープに保持します。

    完全な意味論的混乱への違反。

  • イベント ハンドラー定義と addEventListener 呼び出しの両方を、ターゲットとパラメーターを受け取る関数にカプセル化します。

    スコープを混在させることができますが、近いものです。ただし、注意が必要です。

...他の多くの推奨される回避策の中でも。

必要なのは、イベント ハンドラーに引数を渡して、通常の関数と同じように関数内で使用できるようにすることだけです!

求めすぎですか?

4

5 に答える 5

93

すぐに使える:この古代のパズルを解くには、エレガントなコードを 2 行追加するだけです。

stage.addEventListener(MouseEvent.CLICK, onClick(true, 123, 4.56, "string"));
function onClick(b:Boolean, i:int, n:Number, s:String):Function {
  return function(e:MouseEvent):void {
    trace("Received " + b + ", " + i + ", " + n + " and " + s + ".");
  };
}

しかし、最も重要なことは、リソースを解放するために後でリスナーを削除する必要がある可能性が非常に高いため、+1 行を変数に格納することです。

var functionOnClick:Function = onClick(true, 123, 4.56, "string");
stage.addEventListener(MouseEvent.CLICK, functionOnClick);
function onClick(b:Boolean, i:int, n:Number, s:String):Function {
  return function(e:MouseEvent):void {
    trace("Received " + b + ", " + i + ", " + n + " and " + s + ".");
  };
}

そして、通常どおり削除できます。

trace("Before: " + stage.hasEventListener(MouseEvent.CLICK));
stage.removeEventListener(MouseEvent.CLICK, functionOnClick);
trace("After: " + stage.hasEventListener(MouseEvent.CLICK));

以下は、その使用法を証明するための、より精巧で動的な例です。

function onClick(s:String):Function {
  return function(e:MouseEvent):void {
    trace("The square " + s + " at x = " + e.currentTarget.x + "px was clicked");
  };
}
var myFunctions:Array = new Array();
for (var i:int = 0; i < 10; i++) {
  myFunctions.push(onClick("#" + (i+1)));
}
for (i = 0; i < myFunctions.length; i++) {
  var square:Sprite = new Sprite();
  square.name = "sqr" + i;
  square.addChild(new Bitmap(new BitmapData(20, 20, false, 0)));
  square.x = 5 + 25 * i;
  square.addEventListener(MouseEvent.CLICK, myFunctions[i]);
  stage.addChild(square);
}

動的オブジェクトによるプロパティ、カスタム クラス、緩い関数、スコープの重複はありません。ロジックが期待するとおりです。単に引数を渡すだけです。

すべてのリスナーを適切に削除するには、後で次のようにします。

for (i = 0; i < myFunctions.length; i++) {
  square = stage.getChildByName("sqr" + i) as Sprite;
  trace("Before (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK));
  square.removeEventListener(MouseEvent.CLICK, myFunctions[i]);
  trace("After (#" + (i+1) + "): " + square.hasEventListener(MouseEvent.CLICK));
  stage.removeChild(square);
}

IMHOこれは、最も簡単でありながら最も確実な方法です。

于 2012-11-21T07:53:54.877 に答える
-1

Creyndersの例を少し変更します。

    protected function createHandler(handler:Function, ...args):Function
    {
        var h:Function = function(e:Event = null):void
        {
            trace(args);

            if (handler != null)
                handler(e);
        }
        return h;
    }

    sm.addEventListener(StyleEvent.STYLE_CHANGE, 
            createHandler(updateStyle, 1,true,"Lorem",["a","b","c"]), 
            false, 0, true);

このようにして、元のイベントハンドラーを使用して、それに「引数」を挿入できます。

また、ハンドラーに次の署名を付けることもできます。

protected function myHandler(e:Event, ...args):void;

次に、引数をターゲットハンドラーに直接渡すことができます。

    protected function createHandler(handler:Function, ...args):Function
    {
        var h:Function = function(e:Event = null):void
        {
            //trace(args);

            if (handler != null)
            {
                args.unshift(e);
                handler.apply(this, args);
            }
        }
        return h;
    }

よろしくお願いします

于 2012-11-21T07:32:17.660 に答える