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

自定义事件



为什么要自定义事件?

  • 一个页面,肯定是有许许多多的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.Event
	public 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 new	MyCustomPersionEvent(
				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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值