★再述冒泡机制(思路:发现问题,解决问题)

再述冒泡
思路
1 在as2中发现问题,
2 在as3中解决问题。
3 结合问题,说明冒泡
4 冒泡的问题所在以及解决方法


冒泡很多人在谈,前段时间小弟也是一知半解。弄得云里雾里的。
最近找到一个pdf,呵呵,才算弄明白了点。
把一点学习笔记发出来。

1 在as2中发现问题

我们用一个例子来发现as2中究竟有什么问题。
As2中实现如下效果:
舞台上一个mc,mc中一个btn
点选mc实现拖动mc,鼠标松开停止拖动
点选btn实现mc隐藏。

最容易想到的方法,代码如下:

复制内容到剪贴板
代码:
mc.onPress = function() {
    this.startDrag();
};
mc.onRelease = function() {
    this.stopDrag();
};
mc.btn.onPress = function() {
    mc._visible=false
};

表面来看,这个思路是正确的。(实际上没什么思路可言,很简单的方法。)
下面发fla,大家下载试试。
实际怎么样?
当然是不能实现。
问题来了:
点击btn,不能触发btn的动作!!!!
解释如下:
1 因为btn处于mc内部,mc被加上了事件以后,按照as2的事件机制,mc内部的btn甚至是其他的元件都不能接受事件。或者可以认为mc的事件覆盖了mc中其他元件的事件。
2 从非冒泡机制来说(as2就是非冒泡),在btn上点击鼠标,首先接受到点击事件的自然是btn的上一层(也就是mc),然后才是btn元件。Mc先接受到点击事件,触发相关的函数。然后呢?我们要实现的点击btn的效果没了。我们可以认为mc把我们的鼠标点击事件据为私有了,不再往下传递。(如果是冒泡机制的话,这个动作就回继续往下传递到btn,然后btn会执行。)那么这种效果在as2中还能实现么?答案自然是肯定的,不过方法就复杂了。
这里就不讨论了。As3已经成为主流。

但是as3中的冒泡机制,让我们可以简单的解决这样的难题。

2 在as3中解决问题:
下面来看as3中怎么实现。
代码如下:

复制内容到剪贴板
代码:
import flash.events.*;
mc.addEventListener(MouseEvent.CLICK,mcfunction);
mc.btn.addEventListener(MouseEvent.CLICK,btnfucntion);
function mcfunction(event:MouseEvent) {
    trace("mc click");
}
function btnfucntion(event:MouseEvent) {
    trace("btn click");
}

原文件下载见底部"as3"文件
能实现了吧?
看看代码就觉得,好像没用什么特别的解决方法,就加两个侦听函数,就搞定了。
这个代码自然的不能再自然了,就好像做flash 先的安装软件一样。
但是如此自然的代码下面,使as3的冒泡机制在提供支持。

3 结合问题,说明冒泡机制:
Chm中有一个冒泡机制的图,相信大家都已经看过了
这里我联系实例,另外做一个图,帮助各位理解。

上图也就是在as3中实现我们文章开始提出的例子的工作原理。
下面详细描述一下
捕获阶段:
鼠标在btn上发出点击事件,首先捕捉到该事件的事stage.,然后事件往下传递到mc,再到btn..(如果鼠标事件发生在btn按钮中的一个label上,那么该事件还会继续向下传递,直到找到label元件。)
     As2中,一旦找到了可以相应事件的函数,就停止了,不会往下传递。这个道理应该说明白了

目标阶段:
找到我们的鼠标最底层的目标,也就是btn以后,那么就开始执行btn的侦听函数了。
    如果鼠标事件发生的所在位置,是mc中的btn中的一个label。那么将先执行label的侦听函数。(当然我们的例子中没有label)

冒泡阶段:
执行了目标阶段的侦听函数以后,开始冒泡。
换一个说法是,返回btn的父级元件mc,如果能找到相关的侦听函数,那么就执行,如果没有,就继续往上冒泡到btn的父级元件mc的父级元件stage。看能不能找到相关的侦听函数。
注意一个:首先执行的函数一定是目标对象的侦听函数。就像我们上面的例子一样,点击btn会先trace(“btn click”),然后冒泡到mc,执行trace(“mc click”)..然后继续往上,如果stage我们也加一个侦听函数,执行语句,那么还会继续执行 trace(“stage click”).
到达stage顶层了,冒泡结束。

说到这里,各位看官也应该明白了as3的冒泡究竟是干什么用的了

4 冒泡的问题所在以及解决方法  
冒泡也有问题,并不是说它有缺陷,因为出现问题无法避免。
  问题在于,
  假如在上面的例子中,我们不想在点击btn冒泡阶段中执行mc的侦听函数,我们只想执行btn的侦听函数。怎么解决?
同样的问题延伸出去,可以得到很多扩展和应用。
那么我们需要阻止他的冒泡的时候执行相关的侦听函数。
Chm中的方法有
复制内容到剪贴板
代码:
stopImmediatePropagation():void
防止对事件流中当前节点中和所有后续节点中的事件侦听器进行处理。
stopPropagation():void
防止对事件流中当前节点的后续节点中的所有事件侦听器进行处理。
用来修改我们上面的例子
代码如下:
复制内容到剪贴板
代码:
import flash.events.*;
mc.addEventListener(MouseEvent.CLICK,mcfunction);
mc.btn.addEventListener(MouseEvent.CLICK,btnfucntion);
function mcfunction(event:MouseEvent) {
    trace("mc click");
}
function btnfucntion(event:MouseEvent) {
    trace("btn click");
    event.stopPropagation();//修改在此处。简单一句,解决问题
}
现在可以试试,点击btn运行得到的结果就是
复制内容到剪贴板
代码:
btn click
说明,已经防止了冒泡阶段中对mc侦听函数的处理。也就没有trace(“mc click”)了

As3事件机制远远不像这里写的那么简单,还有很多东西需要研究。
本文只为抛砖引玉,让各位能先了解一下冒泡机制。
希望能多的朋友能提供相关的学习资料

摘自《AS3编程》

只要发生事件, Flash Player 就会调度事件对象。如果事件目标不在显示列表中,则 Flash
Player 将事件对象直接调度到事件目标。例如,Flash Player 将 progress 事件对象直接调度
到 URLStream 对象。但是,如果事件目标在显示列表中,则 Flash Player 将事件对象调度
到显示列表,事件对象将在显示列表中穿行,直到到达事件目标。
“事件流”说明事件对象如何在显示列表中穿行。显示列表以一种可以描述为树的层次结构
形式进行组织。位于显示列表层次结构顶部的是舞台,它是一种特殊的显示对象容器,用作
显示列表的根。舞台由 flash.display.Stage 类表示,且只能通过显示对象访问。每个显示对
象都有一个名为 stage 的属性,该属性表示应用程序的舞台。
当 Flash Player 调度事件对象时,该事件对象进行一次从舞台到“目标节点”的往返行程。
DOM 事件规范将目标节点定义为代表事件目标的节点。也就是说,目标节点是发生了事件
的显示列表对象。例如,如果用户单击名为 child1 的显示列表对象, Flash Player 将使用
child1 作为目标节点来调度事件对象。
从概念上来说,事件流分为三部分。第一部分称为捕获阶段,该阶段包括从舞台到目标节点
的父节点范围内的所有节点。第二部分称为目标阶段,该阶段仅包括目标节点。第三部分称
为冒泡阶段。冒泡阶段包括从目标节点的父节点返回到舞台的行程中遇到的节点。
如果您将显示列表想像为一个垂直的层次结构,其中舞台位于顶层(如下图显示),那么这
些阶段的名称就更容易理解了:

如果用户单击 Child1,Flash Player 将向事件流调度一个事件对象。如下面的图像所示,对
象的行程从 Stage 开始,向下移动到 Parent,然后移动到 Child1,再“冒泡”返回到
Stage:在行程中重新经过 Parent,再返回到 Stage。

在该示例中,捕获阶段在首次向下行程中包括 Stage 和 Parent。目标阶段包括在 Child1 花
费的时间。冒泡阶段包括在向上返回到根节点的行程中遇到的 Parent 和 Stage。
事件流使现在的事件处理系统比 ActionScript 程序员以前使用的事件处理系统功能更为强
大。早期版本的 ActionScript 中没有事件流,这意味着事件侦听器只能添加到生成事件的对
象。在 ActionScript 3.0 中,您不但可以将事件侦听器添加到目标节点,还可以将它们添加
到事件流中的任何节点。
当用户界面组件包含多个对象时,沿事件流添加事件侦听器的功能十分有用。例如,按钮对
象通常包含一个用作按钮标签的文本对象。如果无法将侦听器添加到事件流,您将必须将侦
听器添加到按钮对象和文本对象,以确保您收到有关在按钮上任何位置发生的单击事件的通
知。而事件流的存在则使您可以将一个事件侦听器放在按钮对象上,以处理文本对象上发生
的单击事件或按钮对象上未被文本对象遮住的区域上发生的单击事件。
不过,并非每个事件对象都参与事件流的所有三个阶段。某些类型的事件(例如 enterFrame
和 init 类型的事件)会直接调度到目标节点,并不参与捕获阶段和冒泡阶段。其它事件可
能以不在显示列表中的对象为目标,例如调度到 Socket 类的实例的事件。这些事件对象也
将直接流至目标对象,而不参与捕获和冒泡阶段。
要查明特定事件类型的行为,可以查看 API 文档或检查事件对象的属性

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值