这个按道理应该放在最开始讲的,我把放到了最后面,却是想做个总结。这篇和后面的两篇,我为大家讲解下事件总纲。总纲这个词是我自己定义的,意思是所有事件的基础。用通俗的话来说,就是其他事件,也可以应用这些方法和属性。
1. target和currentTarget
在Event类里,有两个重要的公共属性,target和currentTarget。但很多朋友可能搞不清这两者的区别是什么,往往是猜着用的。
我通过例子来尽量说清楚这两者的区别:
(1) 我们在舞台上创建一个MC,实例名为t1,如下图所示:
然后在第一帧写入代码如下:
function p1(event:MouseEvent):void
{
trace("target:"+event.target.name)
trace("currentTarget:"+event.currentTarget.name);
}
t1.addEventListener(MouseEvent.CLICK, p1);
运行后,输出结果如下:
target:t1
currentTarget:t1
此时,两者指向相同的对象。
(2) 我们在MC的内部再创建一个MC,实例名为t2,如下图所示:
代码不变,运行后点击t2区域,输出:
target:t2
currentTarget:t1
说明:如果在一个显示列表中,Flash Player 始终会选择最里面的那个对象作为target目标。
(3) 我们把t2也注册一个侦听器,代码如下:
function p1(event:MouseEvent):void
{
trace("target:"+event.target.name)
trace("currentTarget:"+event.currentTarget.name);
}
t1.addEventListener(MouseEvent.CLICK, p1);
t1.t2.addEventListener(MouseEvent.CLICK, p1);
运行后点击t2区域,输出:
target:t2
currentTarget:t2
target:t2
currentTarget:t1
说明:currentTarget指向的只是当前事件正在处理的对象。
总结:
1. target指向的是最底层的那个目标,而currentTarget指向的是事件正在处理的目标。
2. target指向的对象不会变,但currentTarget指向的目标会产生变化。
3. 如果目标不在显示列表中,比如Timer类,推荐使用target,因为他是固定的。如果目标在显示列表中,推荐使用currentTarget。因为target的对象虽然不会变,但复杂的MC,往往我自己都不知道点到什么了。
呵呵,不知道现在,大家是否清楚这两者之间的区别了。
2. 尴尬的比较:stopPropagation 和 stopImmediatePropagation
帮助文档上,这两个方法的区别还是很明显的,“stopPropagation不会影响当前节点中的任何事件侦听器,stopImmediatePropagation会影响当前节点中的事件侦听器。”
但不知道大家对这句话的理解是怎么样的,我们来做几个实例吧:
(1) 舞台结构还是如上例。首先,我们来测试下,对同一个对象的两个先后事件,这两个方法是否有区别,代码如下:
function p1(event:MouseEvent):void
{
trace("t1:"+event.type);
event.stopPropagation(); //这里进行替换测试
}
t1.addEventListener(MouseEvent.MOUSE_DOWN, p1);
function p2(event:MouseEvent):void
{
trace("t1:"+event.type);
}
t1.addEventListener(MouseEvent.CLICK, p2);
经运行,无论是stopPropagation还是stopImmediatePropagation,输出结果均为:
t1:mouseDown
t1:click
也就是说,对同一对象的两个先后事件,这两个方法毫无区别。
(2) 然后我们测试下,对不同对象的同一事件,这两个方法是否有区别,代码如下:
function p1(event:MouseEvent):void
{
trace("t1:"+event.type);
}
t1.addEventListener(MouseEvent.MOUSE_DOWN, p1);
function p2(event:MouseEvent):void
{
trace("t2:"+event.type);
event.stopPropagation(); //这里进行替换测试
}
t1.t2.addEventListener(MouseEvent.MOUSE_DOWN, p2);
经运行,无论是stopPropagation还是stopImmediatePropagation,输出结果均为:
t2:mouseDown
说明t1的冒泡均被中止了。
也就是说,对不同对象的同一事件,这两个方法也是毫无区别。
(3) 当时,我真的很郁闷,心想,这两个方法的区别到底在哪里呢?去网上找了找相关帖子,有一篇帖子给出了一个例子,于是就有了我下面的第三次测试:
对相同的对象采用相同的事件!代码如下:
function p1(event:MouseEvent):void
{
trace("t1:"+event.type);
event.stopPropagation();
}
t1.addEventListener(MouseEvent.MOUSE_DOWN, p1);
function p2(event:MouseEvent):void
{
trace("t2:"+event.type);
}
t1.addEventListener(MouseEvent.MOUSE_DOWN, p2);
经运行,终于发现区别,用stopPropagation方法,输出结果如下:
t1:mouseDown
t2:mouseDown
用stopImmediatePropagation方法,输出结果如下:
t1:mouseDown
开心啊,激动啊,终于有区别了啊!可是转念一想,不对啊,这样有个鸟用啊!我吃饱了撑的要在同一个目标上侦听两个相同事件?
然后再在网上一阵猛找,可惜,没有找到相关说明了。但后来,本人在研究EventDispatcher类的时候,终于注意到了一个被忽视的细节:
原来,addEventListener方法有个特殊的属性:useCapture。默认值是false,代表侦听器将在事件流的目标阶段和冒泡阶段处于活动状态。如果我们设置为true,侦听器将在事件流的捕获阶段成为活动状态。所以如果我们要在事件流的所有阶段侦听某一事件,就需要调用 addEventListener() 两次,第一次将 useCapture 设置为 true,第二次将 useCapture 设置为 false。
也就是在这个时候,上述的两个方法终于用了用武之地。
但是,这个属性,似乎非常不常用,我是从来没用过。即使用到这个属性,也不一定需要用到stopPropagation 和 stopImmediatePropagation。
所以,一般来说,你可以认为,stopPropagation 和 stopImmediatePropagation完全没有区别。真的,你可以这么认为的!