韩式写真摄影工作室:谈谈事件机制

来源:百度文库 编辑:九乡新闻网 时间:2024/10/04 04:50:50
谈谈事件机制 ===============================================================================================================================
    (一)什么是事件?
    让我们来举几个例子让大家明白其中的道理

    举例一--天地会会员注册量超过20000   
    事件类型:天地会新闻
    事件类型再细分: 有关注册量的新闻
    事件时间:2008年11月27日
    事件敏感数字: 20000

    举例二---鼠标滚轮向上滑动

    事件类型:MouseEvent
    事件类型再细分:滚轮动作
    事件信息:向上滚动(dlta>0)

    举例三---用户按下字母键F

    事件类型:keyBoardEvent
    事件类型再细分:键盘被按下
    事件信息   :keyCode=45

    由上面三个例子可以看出,事件没什么好神奇的,事件不过就是新闻或者消息罢了
    新闻有政治的,有八卦的,有科技的,也有经济的。所以事件也可以分类,有鼠标事件、键盘事件、加载完成等等事件。
    新闻(消息)有发生时间,发生地点,相关人物,所以AS3的事件里面也包含各种信息。鼠标事件里面可以有鼠标点了哪一个Sprite,鼠标点击处的坐标等信息、而键盘事件里面则可以有键盘是被按下还是被弹起,按下键的ASCII值,以及Ctrl是否被按下等信息。
  1. 经典语录:一切都是对象(All is object)
复制代码 一个数组是一个数组对象,一个影片剪辑是一个影片剪辑对象,甚至还可以说一个int值也是一个int对象,所以把AS3里面的事件叫做事件对象就不足为奇了。大家不要把事件对象理解成抛出事件的对象或者事件流经的对象,"事件对象"是一个消息。事件对象里面包含事件的相关信息。为了容易理解,在这里我们暂时把事件对象比喻成一个信封(事件对象),信封里面装着信(事件对象的具体信息)。
===============================================================================================================================
    (二)什么是目标对象(target),当前目标对象(currentTarget)?

    首先要知道所有的事件都是由FlashPlayer的事件管理中心发出的,当鼠标点击一个Sprite时,FlashPlayer会向这个Sprite发送一个鼠标事件对象(MouseEvent)从而形成一个事件流,而同在舞台的另一个Sprite则不会收到FlashPlayer发出的事件,因为事件流是流向前一个Sprite的不会经过第二个Sprite。
   
    熟悉AS2的人知道,在AS2时代很多在内层的MovieClip都被剥夺了响应鼠标的权力。AS3为我们提供了强大的DOM事件流机制,使得所以对象都有平等的权力接收到相关事件信息。
   
    事件流的三个阶段:
  1.     1 捕获阶段 (EventPhase.CAPTURING_PHASE)包括从舞台到目标节点范围内的所有节点
  2.     2 目标阶段 (EventPhase.AT_TARGET)权包括目标节点
  3.     3 冒泡阶段 (EventPhase.BUBBLING_PHASE)从目标节点的父节点返回到舞台的行程中遇到的节点
复制代码 不是所有的事件都有这三个阶段。如Timer、URLLoader,它们的事件对象将直接派送给目标对象(target).它们只包含目标阶段而没有捕获阶段和冒泡阶段。它们不会像显示对象容器(DisplayObjectContainer)那样有可能被一个DisplayObjectContainer对象包含或者自己包含一个DisplayObjectContainer对象,它们往往是单独存在的。

    对于可显示对象我们应建立显示对象列表的概念,一个即使对象有大小有颜色,如果不被addChild到舞台(或者已经在舞台上的显示对象)里是不会显示的,这样FlashPlayer在渲染时候只需要渲染显示对象列表中的对象即可,可以大大节约资源。

    当一个显示对象不在显示列表中时,FlashPlaye会把事件直接派送给它,这个时候就没有事件流,也没有捕获阶段和冒泡阶段,only目标阶段。
    例如:
  1. var i=0;
  2. var s = new Sprite();
  3. s.addEventListener(Event.ENTER_FRAME,onEnter);
  4. function onEnter(evt:Event) {
  5.         i++;
  6.         s.name=i;
  7.         trace(s.name);
  8. }
复制代码 对象不在显示列表中也可以接收事件对象(消息)。
   
    但是当多个显示对象重叠的时候,经典的事件流出现了。(附图一)
    首先用代码生成附图一
  1. //outer
  2. var outer = new Sprite();
  3. outer.name="Outer";
  4. outer.graphics.beginFill(0xFF0000);
  5. outer.graphics.drawRect(0,0,100,100);
  6. //mid
  7. var mid = new Sprite();
  8. mid.name="mid"
  9. mid.graphics.beginFill(0x00FF00);
  10. mid.graphics.drawRect(0,0,50,50);
  11. //inner
  12. var inner = new Sprite();
  13. inner.name="inner";
  14. inner.graphics.beginFill(0x0000FF);
  15. inner.graphics.drawRect(0,0,25,25);
  16. //addChild
  17. outer.addChild(mid);
  18. mid.addChild(inner);
  19. addChild(outer);
  20. outer.x=outer.y=100;
  21. //添加侦听器
  22. outer.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
  23. inner.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
  24. mid.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
  25. function mouseDownHandler(evt:MouseEvent){
  26.         trace("事件流当前阶段:"+evt.eventPhase)
  27.         trace("鼠标点击处最内层的显示对象(target)是:" + evt.target.name)
  28.         trace("事件当前流经显示对象(currentTarget)是:"+evt.currentTarget.name)
  29.         trace("===============================================================")
  30.    
  31.         }
复制代码 鼠标点击蓝色部分时的输出
  1. 事件流当前阶段:2
  2. 鼠标点击处最内层的显示对象(target)是:inner
  3. 事件当前流经显示对象(currentTarget)是:inner
  4. ===============================================================
  5. 事件流当前阶段:3
  6. 鼠标点击处最内层的显示对象(target)是:inner
  7. 事件当前流经显示对象(currentTarget)是:mid
  8. ===============================================================
  9. 事件流当前阶段:3
  10. 鼠标点击处最内层的显示对象(target)是:inner
  11. 事件当前流经显示对象(currentTarget)是:Outer
  12. ===============================================================
复制代码 由附图一我们可以看到三个不同的Sprite---outer(红色),mid(绿色),inner(蓝色)。outer里面包含mid,mid里面包含inner

    当我们用鼠标点击蓝色部分时,鼠标点击处最内层的对象是inner,如前面所说,AS3中要保证所有对象都有平等接收事件消息的权力。捕获阶段便是为解决这一问题而设的,

    1.首先PlashPlayer发出一个鼠标事件对象(一个信封),把它送到显示对象列表(outer,mid,inner都在显示列表中)。
    2.捕获阶段的任务是找到鼠标点击处最内层的对象,也就是目标对象(target),所以事件对象(FlashPlayer寄出来的那封信)沿着显示对象列表一直往下找,先找到outer再找到mid,再找到inner,在这个找的过程中,事件在流动,所以形成了事件流。
    3.终于我们找到了目标对象(target)inner,目标阶段也就到了,FlashPlayer终于保证了最基层群众也有知情权。
    4.现在基层群众接收到了事件,它看完之后,事件对象(那封信)开始往回上传了,传说中的冒泡阶段开始了,outer,mid又一次接收到了同一个事件。

    所以目标对象(target)一般来说都是最里层的对象也就是FlashPlayer要找的基层群众,在上面的例子中target始终是是inner
    当前对象(currentTarget)则是注册侦听器的对象,一般是容器也是事件流当前流经的注册了侦听器的对象,在上面的例子中currentTarget先后是inner,mid,outer

    正确地区分target和currentTarget非常重要。如果我们要用Sprite做一个按钮,按钮里面在放一个TextField用来显示按钮名称(附图二),代码如下:
  1. var button=new Sprite();
  2. button.graphics.beginFill(0xFF0000);
  3. button.graphics.drawRect(0,0,50,25);
  4. var t=new TextField();
  5. t.text="START";
  6. button.addChild(t);
  7. addChild(button);
  8. button.x=button.y=100;
  9. //button.mouseChildren=false
  10. addEventListener(MouseEvent.MOUSE_DOWN,mouseDownHandler);
  11. function mouseDownHandler(evt:MouseEvent) {
  12.         evt.target.visible=false;
  13. }
复制代码 我们的本意是在按下START按钮后让其消失,但是如果我们的鼠标点到了TextField上时,发现消失的是TextField而不是button。因为鼠标点击处最内层的对象也就目标对象target是t(TextField对象)而不是button(Sprite对象),很多时候新手会被这种情况搞得一头雾水,如何解决这一问题?只要把button的mouseChildren属性设为false即可让其子对象不参与响应鼠标事件,这样便可以解决target和currentTarget混淆的问题。如果子对象不需要参与鼠标事件响应,完全可以把容器的mouseChildren属性设为false,还可以节约资源!