Flex之旅:第一部分:flex必备基础知识积累(2)---自定义事件以及事件数据传递

来源:互联网 发布:钢结构三维详图软件 编辑:程序博客网 时间:2024/06/05 04:34

自定义事件



为什么要自定义事件?

  • 一个页面,肯定是有许许多多的components组成的;
  • 为了方便管理和复用,我们要按照逻辑划分,把一个页面划分成多个小的页面(main包含,a包含,b包含,c是叶子节点)。
  • 页面a和页面b之间,或者页面a和主页面(main)之间要相互通信,
  • 通信,就意味着有页面之间有数据传递,
  • 如果想在数据传递的同时,降低页面与页面之间的耦合度,就要使用事件去传递数据。
  • 虽然每个component都自带默认事件,但无法满足如上情况的要求,因此需要自定义事件。
  • 自定义事件一定是为了一个自定义页面所服务的(同样的,一个自定义页面也会包含许多components)


如何自定义事件?
  • 首先这个class 要继承 flash.events.Event
  • 构造函数,要向上传递参数:super();
  • 要重写clone()方法。
  • 要有,自定义的事件类型定义。
  • 要有,事件要传递数据类型的定义。
  • (好吧,目前总结这么多害羞
  • 代码如下:

package events{import flash.events.Event;import mx.events.FlexEvent;import vo.Persion;// 继承flash.events.Eventpublic class MyCustomPersionEvent extends Event{// 自定义的事件类型public static const AGE_CHANGED:String = "ageChanged";public static const NAME_CHANGED:String = "nameChanged";// 事件要传递数据的定义public var persion:Persion;// 构造函数的向上通知public function MyCustomPersionEvent(type:String,persion:Persion=null, bubbles:Boolean=false, cancelable:Boolean=false){super(type, bubbles, cancelable);this.persion = persion;}// 覆盖clone()override public function clone():Event{return newMyCustomPersionEvent(super.type,this.persion, super.bubbles,super.cancelable);}}}



这里面要有一些注意事项:
  • “自定义事件类型”的命名规则:其实也没有什么规则啦,flex都会识别的。但是查看了,flex现有的事件类之后(参考:mx.events.FlexEvent),还是按照现有的事件类命名规则就好:
    • 变量修饰:public static const
    • 变量名字都是大写,单词之间,用下划线“_”连接
    • 变量的值:第一个单词的首字母小写,后续的单词首字母大写,单词之间没有划线“_”连接。
  • "构造函数向上通知":
    • 呵呵,flex的类,构造函数里面,super没有强制在方法的第一行。个人觉得还是放在第一行吧吐舌头
    • super(type, bubbles, cancelable) 这句必不可少,构造函数负责向上通知,包括设定事件是否冒泡奋斗(度娘:flex事件的冒泡机制)
    • 在构造event时候,type,不要随便穿入,一定要使用事先定义好的常量。在如上的类中,就要使用 MyCustomPersionEvent.AGE_CHANGED  或 MyCustomPersionEvent.NAME_CHANGED
  • 一定要覆盖clone()方法:
    • 当一个event被二次派发出去的时候,会调用此方法。如果没有覆盖clone()方法,那么就会调用Event.clone(),后果可想而知。
    • clone()方法内部就是,调用构造函数,其参数级别,super和this,清晰可见。



自定义事件的使用和数据传递


大致使用步骤:
  • 让自定义事件和一个自定义view绑定:<fx:Metadata/>
  • 绑定之后,需要自身把自定义的事件,派发出去。
  • 自定义事件的派发,一定是借助于一个现有的事件响应的时候。
  • 详细代码如下:

自定义的view: Persionform.mxml  在form package下

<?xml version="1.0" encoding="utf-8"?><mx:Box xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" label="{persion.id}" ><fx:Declarations></fx:Declarations><fx:Metadata>[Event(name="ageChanged", type="events.MyCustomPersionEvent")][Event(name="nameChanged", type="events.MyCustomPersionEvent")]</fx:Metadata><fx:Script><![CDATA[import spark.events.TextOperationEvent;import events.MyCustomPersionEvent;import vo.Persion;[Bindable] public var persion:Persion;protected function aa_changeHandler(event:TextOperationEvent):void{persion.age = new Number(aa.text) ;this.dispatchEvent(new MyCustomPersionEvent(MyCustomPersionEvent.AGE_CHANGED,persion));}protected function nn_changeHandler(event:TextOperationEvent):void{persion.name = nn.text;this.dispatchEvent(new MyCustomPersionEvent(MyCustomPersionEvent.NAME_CHANGED,persion))}]]></fx:Script><s:BorderContainer><s:layout><s:HorizontalLayout horizontalAlign="center" verticalAlign="middle" /></s:layout><mx:Form><mx:FormItem label="Age"><s:TextInput id="aa" text="{persion.age}" change="aa_changeHandler(event)"/></mx:FormItem><mx:FormItem label="Name"><s:TextInput id="nn" text="{persion.name}" change="nn_changeHandler(event)"/></mx:FormItem></mx:Form></s:BorderContainer></mx:Box>

请看:

  • <fx:Metadata/> 标签,让自定义事件MyCustomPersionEvent与 Persionform.mxml 绑定到了一起:
    • [Event(name="ageChanged", type="events.MyCustomPersionEvent")]  描述了,Persionform.mxml会派发events.MyCustomPersionEvent事件,事件的名称是“ageChanged”
    • 注意name 所对应的值 就是MyCustomPersionEvent.AGE_CHANGED的值,type所对应的值,一定是包.类名
    • 同样的 [Event(name="nameChanged", type="events.MyCustomPersionEvent")] 描述了, Persionform.mxml会派发events.MyCustomPersionEvent事件,事件的名称是“nameChanged”
  • 自定义事件的派发,一定是借助于现有的事件,根据自己想要的业务逻辑给派发出去的。
    • 在这里,自定义事件,有两个类型,分别针对于age修改和name修改
    • age和name的textInput本身就有change事件,
    • 监听change事件,借助于现有的change事件,将自定义事件(MyCustomPersionEvent)的相关类型(nameChanged || ageChanged)派发出去
  • 事件的数据传递
    • this.dispatchEvent(new MyCustomPersionEvent(MyCustomPersionEvent.AGE_CHANGED,persion));
    • persion就是自定义的数据。
    • 在这里,我只是,将age || name 的修改结果,放在person对象里面,让后让MyCustomPersionEvent事件将person对象传递出去(dispatchEvent())。
  • 自定义事件派发成功了,并不意味着,必须要监听(就像textInput的change事件监听不是必须的,是根据自己的业务逻辑来的)。
  • 如下的业务逻辑是:
    • 主程序页面,button会创建多个Persionform.mxml页面实例,
    • 每个Persionform.mxml页面会维护一个person对象,
    • 主程序要监听每个Persionform.mxml页面的对person对象的修改情况
    • 代码如下:

MainTest.mxml


<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"    xmlns:s="library://ns.adobe.com/flex/spark"    xmlns:mx="library://ns.adobe.com/flex/mx"     minWidth="955" minHeight="600" xmlns:form="form.*"      ><fx:Script><![CDATA[import form.Persionform;import mx.events.FlexEvent;import events.MyCustomPersionEvent;import vo.Persion;protected function b_clickHandler(event:MouseEvent):void{var persion:Persion = new Persion();persion.age = 18;persion.name = "郭美美";var persionForm:Persionform = new Persionform();persionForm.persion = persion;persionForm.addEventListener(MyCustomPersionEvent.AGE_CHANGED,ageChangedHandler);persionForm.addEventListener(MyCustomPersionEvent.NAME_CHANGED,nameChangedHandler);tn.addChild(persionForm);tn.selectedChild = persionForm;persion.id = "persion"+tn.selectedIndex;}private function ageChangedHandler(event:MyCustomPersionEvent):void{if(event.target is Persionform){var pf:Persionform = event.target as Persionform;trace("Persionform ("+pf.label+") ageChanged:" + event.persion.age);//this.dispatchEvent(event); // 这里二次转发event的时候,会调用内部的clone()方法}}private function nameChangedHandler(event:MyCustomPersionEvent):void{if(event.target is Persionform){var pf:Persionform = event.target as Persionform;trace("Persionform ("+pf.label+") nameChanged:" + event.persion.name);}}]]></fx:Script><fx:Declarations><!-- Place non-visual elements (e.g., services, value objects) here --></fx:Declarations><s:VGroup gap="20" width="100%"><s:Button id="b" click="b_clickHandler(event)" label="add"></s:Button><mx:TabNavigator id="tn" width="70%" height="100%"/></s:VGroup></s:Application>

请看这里:
  • persionForm.addEventListener(MyCustomPersionEvent.AGE_CHANGED,ageChangedHandler);
    persionForm.addEventListener(MyCustomPersionEvent.NAME_CHANGED,nameChangedHandler);
  • 为每个persionForm添加事件监听。
  • 当persionForm内部派发MyCustomPersionEvent.AGE_CHANGED事件的时候,ageChangedHandler方法就会被调用
  • 当persionForm内部派发MyCustomPersionEvent.NAME_CHANGED事件的时候,nameChangedHandler方法就会被调用
  • 整个过程,称之:事件的监听和响应过程。

注意:
  • 因为persionForm自身会派发出MyCustomPersionEvent.AGE_CHANGED 和 MyCustomPersionEvent.NAME_CHANGED事件
  • 所以,想要监听MyCustomPersionEvent事件,也要在persionForm身上添加!!!!:persionForm.addEventListener(MyCustomPersionEvent.AGE_CHANGED,ageChangedHandler);
  • 幸好,MainTest.mxml主程序页面里面可以得到persionForm实例,然后为每个persionForm实例添加事件监听。
  • 打个比方,如果在MainTest.mxml主程序页面里面没有(或者多级页面嵌套太深,无法获得)获得persionForm实例,但是想要在主程序页面里面监听MyCustomPersionEvent事件,我们应该怎么办???
    • 只能用flex事件的冒泡特性了。
    • 此修改后的demo利用冒泡特性,监听自定义事件的实现,代码修改后如下(请看,代码注释部分的讲解)


自定义的view: Persionform.mxml  在form package下(事件冒泡功能版本)

<?xml version="1.0" encoding="utf-8"?><mx:Box xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark" xmlns:mx="library://ns.adobe.com/flex/mx" label="{persion.id}" ><fx:Declarations></fx:Declarations><fx:Metadata>[Event(name="ageChanged", type="events.MyCustomPersionEvent")][Event(name="nameChanged", type="events.MyCustomPersionEvent")]</fx:Metadata><fx:Script><![CDATA[import spark.events.TextOperationEvent;import events.MyCustomPersionEvent;import vo.Persion;[Bindable] public var persion:Persion;protected function aa_changeHandler(event:TextOperationEvent):void{persion.age = new Number(aa.text) ;this.dispatchEvent(new MyCustomPersionEvent(MyCustomPersionEvent.AGE_CHANGED,persion,true)); // true,让该事件可以冒泡}protected function nn_changeHandler(event:TextOperationEvent):void{persion.name = nn.text;this.dispatchEvent(new MyCustomPersionEvent(MyCustomPersionEvent.NAME_CHANGED,persion,true)) // true,让该事件可以冒泡}]]></fx:Script><s:BorderContainer><s:layout><s:HorizontalLayout horizontalAlign="center" verticalAlign="middle" /></s:layout><mx:Form><mx:FormItem label="Age"><s:TextInput id="aa" text="{persion.age}" change="aa_changeHandler(event)"/></mx:FormItem><mx:FormItem label="Name"><s:TextInput id="nn" text="{persion.name}" change="nn_changeHandler(event)"/></mx:FormItem></mx:Form></s:BorderContainer></mx:Box>



MainTest.mxml(监听冒泡的事件)

<?xml version="1.0" encoding="utf-8"?><s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"   xmlns:s="library://ns.adobe.com/flex/spark"   xmlns:mx="library://ns.adobe.com/flex/mx"   xmlns:form="form.*"   minWidth="955" minHeight="600"   creationComplete="application1_creationCompleteHandler(event)"><fx:Script><![CDATA[import form.Persionform;import mx.events.FlexEvent;import events.MyCustomPersionEvent;import vo.Persion;protected function b_clickHandler(event:MouseEvent):void{var persion:Persion = new Persion();persion.age = 18;persion.name = "郭美美";var persionForm:Persionform = new Persionform();persionForm.persion = persion;//persionForm.addEventListener(MyCustomPersionEvent.AGE_CHANGED,ageChangedHandler);//persionForm.addEventListener(MyCustomPersionEvent.NAME_CHANGED,nameChangedHandler);tn.addChild(persionForm);tn.selectedChild = persionForm;persion.id = "persion"+tn.selectedIndex;}private function ageChangedHandler(event:MyCustomPersionEvent):void{if(event.target is Persionform){var pf:Persionform = event.target as Persionform;trace("Persionform ("+pf.label+") ageChanged:" + event.persion.age);//this.dispatchEvent(event);}}private function nameChangedHandler(event:MyCustomPersionEvent):void{if(event.target is Persionform){var pf:Persionform = event.target as Persionform;trace("Persionform ("+pf.label+") nameChanged:" + event.persion.name);}}protected function application1_creationCompleteHandler(event:FlexEvent):void{// 假设MainTest.mxml, 没有获得每个persionForm实例,那么将事件的监听,添加到自身上来!this.addEventListener(MyCustomPersionEvent.AGE_CHANGED,ageChangedHandler);this.addEventListener(MyCustomPersionEvent.NAME_CHANGED,nameChangedHandler);}]]></fx:Script><fx:Declarations><!-- Place non-visual elements (e.g., services, value objects) here --></fx:Declarations><s:VGroup width="100%" gap="20"><s:Button id="b" label="add" click="b_clickHandler(event)"></s:Button><mx:TabNavigator id="tn" width="70%" height="100%"/></s:VGroup></s:Application>


我对事件冒泡的个人理解:
  • 事件冒泡的含义就是事件会向上传递。
  • 叶子节点view的事件,如果派发(dispatchEvent())的时候,可以设置bubbles:Boolean=true让其冒泡。
  • 举个例子:
    • main页面,包含a页面,a页面包含b页面,b页面会包含z页面。
    • z页面派发一个事件,并让该事件冒泡。
    • 如果main, a, b 页面都监听了该事件。
    • 当事件派发出来的时候, b, a  , main 页面都会响应,
    • 其事件的传递循序,是根据其层级关机,逐级向上传递,z-> b -> a -> main




Persion.as

package vo{[Bindable]public class Persion{public var id:String;public var age:int;public var name:String;public function Persion(){}}}


运行截图:




我的操作循序是:
  • persion0,先修改age,再修改name
  • persion1,先修改age,再修改name
  • persion2,先修改age,再修改name

控制台显示结果:

Persionform (persion0) ageChanged:181
Persionform (persion0) nameChanged:郭美美1
Persionform (persion1) ageChanged:182
Persionform (persion1) nameChanged:郭美美2
Persionform (persion2) ageChanged:183
Persionform (persion2) nameChanged:郭美美4

0 0
原创粉丝点击