今天写了一些Flex代码,在处理Flex中的事件的时候有一些不明白,仔细看了文档之后终于明白了,在此记录一下。
Flex的事件其实很容易明白,象JAVA语言一样,给某个控件注册一个listener,然后事件发生的时候触发相应的函数,这点我相信大多数人都能够明白。今天我想要说的不是这个,而是更加细节的一些东西。
1.事件的传播过程。
Flex事件有下面三个阶段,当事件发生时依次为:
1.capturing(捕捉)
2.targeting(定位)
3.bubbling(起泡或者回溯)
在这些阶段,程序中从根节点到触发事件的节点(这里的节点就是指可以把整个MXML文件看作是一个XML,那么节点就是各个标签)都有机会来响应事件。假设用户点击了HBox容器中的一个Button,在capturing阶段Flex会检查Application和HBox是否对此事件定义了listener,然后在targeting阶段Flex触发Button的listener,在bubbling阶段Flex又会检查Application和HBox,不过这次的顺序和capturing状态时相反。也就是说,事件发生的时候从根节点到目标节点的父节点有两次机会可以响应事件。
整个事件的这三个阶段也就形成了一个事件流。所以你可以在工作流中的任意节点上注册listener而不用担心不会被触发。还有一点需要说明的是,只有可视的对象(比如一些容器和控件)才有第一个和第三个阶段,而像Socket这种没有界面的对象只能在targeting时被触发,它无法参与第一个和第三个阶段。
虽然每个对象都有两次响应事件的机会,但是在默认情况下,capturing状态时没有对象会响应事件,除非你特别声明要在capturing阶段响应。你可以把addEventListener() 中的use_capture参数设置为true,这样就可以在capturing阶段响应了。但是请注意,一旦在capturing中响应过之后在bubbling阶段就不会再响应了。如果你想要让listener在capturing和bubbling阶段都响应的话,只能两次调用addEventListener() ,一次把use_capture参数设置为true,第二次把它设置为false。
另外,你只能为可以触发一个事件的对象注册此事件的listener。比如,你就不能为一个Form定义一个Click事件,即使它包含一个Button控件,因为Form无法触发Click事件。
你可以使用下面两个函数来中止事件的传播:
stopPropagation()
stopImmediatePropagation()
两者唯一的区别就是stopPropagation()是在当前对象的所有listener执行完毕之后再中止事件的传播,而另外一个是立刻终止。
2.Flex事件中的target和currentTarget
每个Event对象都有target和currentTarget属性,他们可以帮助你跟踪事件传播过程。target指的是触发事件的对象,而currentTarget则是指当前阶段正在被检测到的对象。这样说可能不太好理解,拿上面的那个例子来说吧,在单击事件中target就是那个button(或者其子组件),不会变,而currentTarget则首先是Application,然后是HBox,然后……明白了吧?currentTarget就是当前正在被事件所检测的对象。currentTarget在Flex 1.5中是没有的,是Flex 2新加入的。
当我点击一个Button时,target很有可能并不是这个Button,而是Button的UITextField,就是显示按钮文字的组件。但是大多数时候你都是想操作Button对象或者其他注册了listener的对象,很少有人为UITextField对象注册listener。所以大多数时候你都用currentTarget而不是target来操作他们。举个例子:
<mx:Button label="OK" click="trace(event.currentTarget.label)"/>
在这种情况下,currentTarget就是指Button,而target指什么就取决于用户点击了Button上哪个地方了。所以一般你很少用到target属性,大多数情况下都应该使用currentTarget。
终于总结完了,好像事件还有许多其他我没注意的地方,如果你认为我疏忽了什么,please leave a comment。Thank you.