zoukankan      html  css  js  c++  java
  • Flex的“事件之旅”

    Flex的“事件之旅”

    信号灯的应用中,为什么在点击按钮后,就会自动调用 myEventHandler方法呢?看官答道:“我们把myEventHandler作为事件侦听器注册到了容器ctnButtons上了!”没错,但 是为什么在容器上注册了侦听器,Flash Player就能够调用myEventHandler方法呢?Flash Player如何发现有这样一个侦听器?如果我们在其他的容器,比如ctnButtons的父容器traficLight上为同样的事件注册了侦听器,会 发生什么?Flash Player维护了一个侦听器队列吗?如果是这样的话,那队列中成员的顺序又如何呢?

    其实并没有一个所谓的侦听器队列。但Flash Player确实维护了一个树状列表,即显示列表(详见第7章的7.1.1节“显示列表”(见第126页))。Flash Player创建事件对象,并调度该对象到事件流。事件流就是事件对象在显示列表中的“旅程”。

    当事件发生时(比如用户按下了按钮),Flash Player即创建Event对象,事件之旅也由此刻开始了。然而,事件之旅的起源地并不在“此地”,而是从显示列表的根节点 Stage(flash.display.Stage,一个特别的显示对象容器,显示列表的根节点)开始,然后沿着列表逐级向下,直到发生事件的对象。之 后,又按相反的方向逐级向上回到根节点。没错,事件之旅是个往返旅程。而且,需要强调的是,事件旅程并不包括从根节点Stage对象到发生事件的对象之间 的所有节点,而只涉及发生事件的对象本身和它的父容器。比如,信号灯应用中,Flash Player就不会检查lblLightInfo对象,因为它并不是三个按钮对象的父容器。在这段旅程中,Flash Player逐一检查这些对象是否针对发生的事件注册了侦听器,为事件对象赋值,并调用侦听器。

    概念上,Flex的事件旅程分为三个阶段:捕获阶段、目标阶段和冒 泡阶段,如图6-2所示。既然事件之旅同显示列表密切相关,在旅程开始之前,我列出了信号灯应用的树状显示列表以供参考。同时标出了当用户按下“红色”按 钮时事件旅程的三个阶段。

    图6-2  信号灯应用的显示列表和事件流

    6.2.1  target和currentTarget

    如我们刚才提到的,在事件被触发后,Flash Player就会创建事件对象,并逐一检查“事件旅程”上的节点是否针对发生的事件注册了侦听器,为事件对象赋值,并调用侦听器。事件对象源自 flash.events.Event类。事件对象currentTarget属性的值会在事件流中改变,而target属性则不会变化。(关于事件对 象,我们将在6.3节(见第106页)深入讨论)由此,开发者能够通过currentTarget属性获知事件旅程现在停在了哪个节点上。

    ·      currentTarget属性:事件旅程中,currentTarget属性代表了Flash Player正在检查的节点对象。比如,当Flash Player遍历到ctnButtons对象,那么event.currentTarget就是ctnButtons对象。

    ·      target属性:target属性就是发生事件的对象。在信号灯应用中,event.target就是用户所点击的按钮对象,在事件旅程中,该属性的值 始终不变。信号灯应用中,侦听器myEventHandler利用event.target来获取被点击按钮上的标签数据。此时赋给 event.currentTarget属性的则是HBox容器对象ctnButtons。

    6.2.2  捕获阶段

    在事件发生之 后,Flash Player将沿着显示列表,从根节点Stage开始遍历事件发生对象的所有父对象,这个阶段称之为“捕获阶段”。捕获阶段截止到发生事件对象的直接父对 象。在遍历的过程中,Flash Player会检查是否有节点注册了事件侦听器,并对生成的事件对象赋值,调用事件侦听器方法。

    在信号灯应用中,在事件发 生后,Flash Player将顺序检测Stage、SystemManager、Application、traficLight、ctnButtons,至此为捕获阶 段。

    需要指出的是,在默认情况 下,容器们并不在捕获阶段“侦听”事件。信号灯的应用中,侦听器myEventHandler实际上是在冒泡阶段被调用的。当我们在ctnButtons 上注册侦听器时,默认设置了addEventListener方法的use_capture属性为“false”。如果你希望在捕获阶段调用侦听器,那么 要使用如下代码注册侦听器,见代码6-6:

    代码6-6:在捕获阶段响应按钮事件

    ctnButtons.addEventListener(MouseEvent.CLICK,myEventHandler,true);

    通常情况下,开发者更习惯于 利用事件旅程的目标阶段和冒泡阶段处理事件响应。

    6.2.3  目标阶段

    目标阶段只涉及一个对象, 即发生事件的对象。在目标阶段,事件对象的target和currentTarget对象被赋予相同的值,也就是发生事件的对象。

    在信号灯应用中,如果用户 按下了红色按钮,那么在目标阶段,Flash Player将只检测btnRed对象。如果我们在btnRed按钮上注册侦听器方法(假设为redEventHandler(event Event)),则在目标阶段,系统会调用redEventHandler方法。在该方法中,如果检测event.target和 event.currentTarget属性,将会发现两者均指向btnRed按钮。

    6.2.4  冒泡阶段

    冒泡阶段与捕获阶段涉及的节点完全相同,但遍历顺序却恰好相反。在 Flash Player对发生事件对象检查完毕后,将从其直接父容器开始,沿着显示列表向上,最终返回到Stage根节点。

    在信号灯的应用中,目标阶段结束后,Flash Player将依次检测ctnButtons、traficLight、Application、SystemManager,最终返回到Stage,此 为冒泡阶段,而事件之旅也告一段落。

    6.2.5  信号灯应用的事件之旅

    最后,通过代码再一次体验Flex的“事件之旅”。依然以信号灯的 应用为基础,经过改造的应用代码见代码6-7,新的项目名为EventJourney。

    代码6-7: EventJourney项目代码

    <mx:Script>

           <![CDATA[      

       import mx.controls.Alert;

       private function initApp():void {

           btnRed.addEventListener(MouseEvent.CLICK,myEventHandler);            

           traficLight.addEventListener(MouseEvent.CLICK,myEventHandler);

           ctnButtons.addEventListener(MouseEvent.CLICK,myEventHandler);

           lblLightInfo.addEventListener(MouseEvent.CLICK,myEventHandler);

           this.addEventListener(MouseEvent.CLICK,myEventHandler);

          

           //在捕获阶段调用EventListener

            btnRed.addEventListener(MouseEvent.CLICK,myEventHandler,true);

           traficLight.addEventListener(MouseEvent.CLICK,myEventHandler,true);

           ctnButtons.addEventListener(MouseEvent.CLICK,myEventHandler,true);

           lblLightInfo.addEventListener(MouseEvent.CLICK,myEventHandler,true);

           this.addEventListener(MouseEvent.CLICK,myEventHandler,true);              

       }

       private function myEventHandler(event:Event):void {

           trace(event.currentTarget.toString() + " 在事件阶段" + event.eventPhase);

       }

    ]]>

    </mx:Script>

    在initApp()方法中,我们为btnRed、 traficLight、ctnButtons、lblLightInfo和Application本身(通过this)分两次注册了同一个侦听器 myEventHandler。第二次注册中,我们设置use_capture参数为true。

    在myEventHandler中使用trace方法输出了侦听器 被调用时的当前节点对象和事件所在阶段。事件属性event.eventPhase标志着当前所处事件旅程的阶段。返回值为unit类型,包含了代表着三 个阶段的numeric值。分别为:

    ·      捕获阶段:EventPhase.CAPTURING_PHASE=1;

    ·      目标阶段:EventPhase.AT_TARGET=2;

    ·      冒泡阶段:EventPhase.BUBBLING_PHASE=3。

    在按下红色按钮后,输出结果如代码6-8所示。

    代码6-8: EventJourney项目代码输出结果

    EventJourney0 在事件阶段1

    EventJourney0.traficLight 在事件阶段1

    EventJourney0.traficLight.ctnButtons 在事件阶段1

    EventJourney0.traficLight.ctnButtons.btnRed 在事件阶段2

    EventJourney0.traficLight.ctnButtons 在事件阶段3

    EventJourney0.traficLight 在事件阶段3

    EventJourney0 在事件阶段3

    关于结果的说明:

    ·      尽管我们为btnRed按钮注册了两次侦听器,但是由于Flash Player只在目标阶段检查该按钮,因此侦听器只在目标阶段被调用一次;

    ·      尽管我们为lblLightInfo标签也注册了侦听器,但由于该对象并不在事件旅程覆盖的节点中,因此不会产生任何输出。

  • 相关阅读:
    oracle系列--第五篇 PLSQL连接本地的Oracle数据库
    oracle系列--第四篇 Oracle的卸载
    oracle系列--第三篇 Oracle的安装
    oracle系列--第二篇 oracle下载
    WinForm多语言版本实战项目演练
    从C#垃圾回收(GC)机制中挖掘性能优化方案
    jvm内存模型和垃圾回收
    servlet匹配路径时/和/*的区别(转)
    十大经典排序算法(动图演示)(转)
    排序算法
  • 原文地址:https://www.cnblogs.com/nianshi/p/1746294.html
Copyright © 2011-2022 走看看