【问题标题】:Weird AS3 variable behaviour奇怪的 AS3 变量行为
【发布时间】:2010-09-30 17:07:33
【问题描述】:

好的,这就是我想要做的:

我有一个登陆页面,上面有 3 个按钮,我有 3 个对应的外部 swf 文件,每个按钮一个……所以用户单击一个按钮,相应的 swf 文件被加载到舞台上的一个空 MC 中.现在,这些外部 swf 文件中的每一个还包含多个按钮,并且每个按钮在单击时都会触发一个单击事件,每个 swf 中的每个按钮事件都是基于按钮名称和 swf 文件名唯一命名的(例如:swf1_button1_click)所以在单击按钮后的主 swf 文件中,我循环遍历 3 个主按钮,并将侦听器添加到每个按钮的空持有人剪辑的内容中,以便侦听“swf1_button1_click”、“swf1_button2_click”、“swf2_button1_click”.. 。 等等等等。

现在这一切正常,剪辑正确加载,事件触发并正确听到,这意味着空剪辑确实收到“swf1_btn1_click”事件并且它正确触发与该事件关联的代码,但问题在于被调用的函数, 这里是有问题的代码...

加载外部swf文件的函数:

function loadCommunity(e:MouseEvent) {
 var mLoader:Loader = new Loader();
 var community:String = MovieClip(e.currentTarget).name;
 trace("Loading " + community);
 var mRequest:URLRequest = new URLRequest(DevSite+"/flash/" + community + ".swf?community=" + community);
 mLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, displayCommunity);
 mLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, function(e:ProgressEvent) {
  var percent:Number = e.bytesLoaded / e.bytesTotal;
  percent = Math.round(percent * 100);
  trace(percent + "% loaded");
 });
 mLoader.load(mRequest);
}

分配事件监听器的代码:

function displayCommunity(e:Event) {
 for (var i = 0; i < mcCommunityHolder.numChildren; i++) {
  mcCommunityHolder.removeChild(mcCommunityHolder.getChildAt(i));
 }
 mcCommunityHolder.alpha = 0;
 mcCommunityHolder.visible = true;
 mcCommunityHolder.addChild(e.currentTarget.content);
 TweenLite.to(mcCommunityHolder, 1, {alpha:1, easing:Elastic.easeOut});
 var newClip:MovieClip = MovieClip(mcCommunityHolder.getChildAt(mcCommunityHolder.numChildren - 1));

 for each (var mc:MovieClip in mcCommunities) {
  var commName:String = mc.name.toLowerCase();
  trace(" ... " + commName + " ... ");
  newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
  newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
  newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
  newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); });
 }
}

所以我得到的是:无论外部 swf 的按钮是什么,我点击了其中按钮的事件,就好像我从外部 swf 3 中点击一个按钮......有意义吗?

这里有一个例子:我单击 Button1,外部 swf 1 加载并显示,在外部 swf 1 内我单击按钮 1,该按钮触发其事件“swf1_btn1_click”,主 swf 看到它,但是当这个函数(“communityRegister (commName);") 在侦听器事件中调用,“commName”始终是相同的值(主 swf 的 btn3 应该具有的值)。

因此,我的主要闪存片段将每个外部 swfs 事件视为来自外部 swf 3。我可以解释它的最佳方式是:将“commName:String”视为引用变量,当我在循环的每次迭代中将其辞职,它以前的使用也会更改为新值,所以每次我使用它时,它总是设置为最后一次分配的值...

Gahh !!,真是脑残,哈哈...我以前遇到过很多次这个问题,但从未真正弄清楚。我总是设法重新编写代码,直到它修复它自己,但我厌倦了这样做,我想知道为什么会发生这种情况。我对其他编写我想做的事情的方式不感兴趣,我需要知道导致这种行为的原因,所以不要羞于获得技术;)

提前致谢。

【问题讨论】:

    标签: flash actionscript-3 variables foreach


    【解决方案1】:

    我想你已经发现了问题所在。所有事件侦听器最终都会引用在循环的最后一次迭代中创建的 commName

    有一些方法可以解决这个问题。在我脑海中浮现:

      for each (var mc:MovieClip in mcCommunities) {
      var commName:String = mc.name.toLowerCase();
      trace(" ... " + commName + " ... ");
      newClip.commName = commName;
      newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + e.target.commName); viewLotmap(e.target.commName); });
      newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(e.target.commName); });
      newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + e.target.commName); arielPhotos(e.target.commName); });
      newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + e.target.commName); communityRegister(e.target.commName); });
     }
    

    这里的想法是,由于 MovieClip 是动态的,您可以将 commName 添加为属性。然后,在事件处理程序中,您从 mc 实例中访问该值。

    其他选项可能是这样的:

     for each (var mc:MovieClip in mcCommunities) {
      var commName:String = mc.name.toLowerCase();
      trace(" ... " + commName + " ... ");
      setEvents(newClip,commName);
     }
    
     function setEvents(mc:MovieClip,commName:String):void {
      mc.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
      mc.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
      mc.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
      mc.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); }); 
     }
    

    将 commName 作为参数传递应该可以防止 mcs 共享相同的值。

    【讨论】:

    • 太棒了!我现在明白了,不知道为什么我以前没有看到,但我现在看到了,谢谢你的帮助:)
    【解决方案2】:

    编辑:Doh,哈哈我刚刚重新阅读了上面的评论,这个方法实际上是他提出的第二个建议,我有点渴望尝试他的第一个建议并失败了......哦,好吧,我'我会在这里留下这个原始评论,因为它解释了为什么第一个建议不起作用而第二个建议起作用......

    好的,所以您的解释是合理的,但您的解决方案不起作用...原因如下:

    您说过要向包含“commName”值的影片剪辑添加一个属性,以消除所需的引用变量问题(尽管“commName”只是分配了“mc.name”的值,所以您可以只需使用“mc.name”代替)但引用问题仍然存在,因为我们处于 for 循环中......

    for each (var mc:MovieClip in mcCommunities)...
    

    所以“mc”仍然被视为一个引用变量,我们仍然得到相同的不希望的结果(每个对象事件的行为都好像它在该行中的最后一个对象被单击...)

    那么我们如何解决它...好吧,我最终所做的是将“for each”更改为“for (var i:int...) 并通过使用“getObjectAt( i)” 起初我认为这会起作用,但结果我们仍然有一个变量充当引用,这次它在迭代中是“i:int”......所以这个:

    for (var i:int = 0;  i < mcCommunities.numChildren; i++) {
    MovieClip(mcCommunities.getChildAt(i)).name);   ...
    

    其中 mcCommunities.numChildren 为 3 (0,1,2) 导致 i 等于 3(不是有效索引),当循环退出时以及我设置的任何地方 "MovieClip(mcCommunities.getChildAt(i)).name); "以前现在也有 3 作为 i 的值... fustration

    所以最终的工作解决方案如下:

    function displayCommunity(e:Event) {
        for (var i = 0; i < mcCommunityHolder.numChildren; i++) {
            mcCommunityHolder.removeChild(mcCommunityHolder.getChildAt(i));
        }
        mcCommunityHolder.alpha = 0;
        mcCommunityHolder.visible = true;
        mcCommunityHolder.addChild(e.currentTarget.content);
        TweenLite.to(mcCommunityHolder, 1, {alpha:1, easing:Elastic.easeOut});
    
        for (var j:int = 0;  j < mcCommunities.numChildren; j++) {
            assignListeners(MovieClip(mcCommunityHolder.getChildAt(mcCommunityHolder.numChildren - 1)), MovieClip(mcCommunities.getChildAt(j)).name);
        }
    }
    
    function assignListeners(newClip:MovieClip, commName:String) {
        newClip.addEventListener(commName + "_btnMap", function(e:Event) { trace("clicked: " + commName); viewLotmap(commName); });
        newClip.addEventListener(commName + "_btnLocation", function(e:Event) { trace("clicked: " + commName); viewLocationmap(commName); });
        newClip.addEventListener(commName + "_btnAriel", function(e:Event) { trace("clicked: " + commName); arielPhotos(commName); });
        newClip.addEventListener(commName + "_btnRegister", function(e:Event) { trace("clicked: " + commName); communityRegister(commName); });
    }
    

    我所做的是将 eventListeners 的分配取出并将其放置在一个函数中,所以现在所有之前导致引用变量的地方现在都通过函数参数分配,这些参数只在函数自身的范围内,所以每次你调用它,您可以确定这些值将是您发送的值;) satisfaction

    无论如何,感谢您为我指明了正确的方向,我现在对此有所了解,我可以找到其他一些看似不合逻辑的问题来解决问题:)

    和平

    【讨论】:

      猜你喜欢
      • 2011-12-05
      • 2011-07-11
      • 2021-10-27
      • 2014-06-05
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多