Javascript 是如何决定由哪个元素来处理事件的,以及jQuery
又是如何优化处理这个问题的,这些都涉及到了事件传播。
事件传播策略
当页面内的发生一个事件时,每个层次的 DOM
元素都有机会来处理这个事件,为了弄懂整个过程,举例说明:
<div class="wrapper">
<span class="bar">
<a href="#">segmentfault</a>
</span>
</div>
1.事件捕获
有两种策略来处理事件,第一种是事件捕获。
当采取“事件捕获”策略时,点击 a
标签后,事件首先交给外层的元素,然后再往内交给更具体的元素:
div -> span -> a
2.事件冒泡
另一种策略是“事件冒泡”,事件冒泡与事件捕获刚好相反,当点击 a
标签后,首先会发送到最具体的元素,在这个元素得到响应后,事件会往上冒泡到更外层的元素:
a -> span -> div
一开始,不同的浏览器采用不同的策略来处理事件传播,为了统一化,DOM
标准规定应该同时使用着两种策略,首先通过“事件捕获”来捕获到最具体的元素,接着通过“事件冒泡”返回到DOM
树的顶层。
3.统一策略
同时,我们很容易理解,对于事件的处理程序既可以发生在事件捕获阶段,也可以发生在事件冒泡阶段,jQuery
为了统一策略决定始终在事件冒泡阶段注册事件处理程序。因此,我们可以假定最具体最内层的元素会首先获得响应事件的机会。
事件冒泡的弊端
事件冒泡可能会导致意料之外的行为,例如在响应 mouseout
事件时,依旧是上例,当为最外层的 div
添加一个mouseout
事件。此时,如果鼠标移出 div
区域时,肯定会触发 mouseout
事件绑定的程序,这是我们期望的,但是如果鼠标是从a
元素上离开时,a
元素也会取得一个 mouseout
事件,再通过事件冒泡后,外层的div
也会获得,这显然不是我们想要的。
给 div
添加样式来便于区分:
div {
width: 200px;
height: 200px;
background-color: lightblue;
}
绑定 mouseout
事件到 div
上:
$('div').mouseout(function() {
//触发 `alert`
alert('mouse is out!');
});
当鼠标从淡蓝色的区域移开时,触发 alert
,但是当鼠标放到 a
标签上后再移开,即使没移开 div
区域,同样也会触发 alert
,这显然不是我们希望的,这就是事件冒泡带来的弊端。
这里介绍两种直接简单的方法来解决这个问题。
第一是使用 jQuery
自带的 .hover()
方法,.hover()
方法接受两个函数参数,第一个参数在鼠标进入绑定元素时执行,第二个参数在鼠标移除绑定元素时执行。使用.hover()
方法可以避免事件传播导致的问题。
$('div').hover(function() {}, function() {
alert('mouse is out!');
});
第二种方法是使用 mouseleave
来代替 mouseout
方法。
$('div').mouseleave(function() {
//触发 `alert`
alert('mouse is out!');
});
这两种方法是针对 mouseout
可能出现的问题来解决的,对于事件冒泡可能导致的其他弊端现象,我们需要用更加适用的方法来解决,因为这个知识点在书中的下一个章节介绍,所以我打算在下一篇博文中总结。
什么是JS事件冒泡?:
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。 (摘自网络)
如何来阻止Jquery事件冒泡?
通过一个小例子来解释
<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default5.aspx.cs" Inherits="Default5"%> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head runat="server"> <title>Porschev---Jquery 事件冒泡</title> <script src="jquery-1.3.2-vsdoc.js" type="text/javascript"></script> </head> <body> <form id="form1" runat="server"> <div id="divOne" onclick="alert('我是最外层');"> <div id="divTwo" onclick="alert('我是中间层!')"> <a id="hr_three" href="http://www.baidu.com" mce_href="http://www.baidu.com" onclick="alert('我是最里层!')">点击我</a> </div> </div> </form> </body> </html>
比如上面这个页面,
分为三层:divOne是第外层,divTwo中间层,hr_three是最里层;
他们都有各自的click事件,最里层a标签还有href属性。
运行页面,点击“点击我”,会依次弹出:我是最里层---->我是中间层---->我是最外层
---->然后再链接到百度.
这就是事件冒泡,本来我只点击ID为hr_three的标签,但是确执行了三个alert操作。
事件冒泡过程(以标签ID表示):hr_three----> divTwo----> divOne 。从最里层冒泡到最外层。
如何来阻止?
1.event.stopPropagation();
<script type="text/javascript"> $(function() { $("#hr_three").click(function(event) { event.stopPropagation(); }); }); <script>
再点击“点击我”,会弹出:我是最里层,然后链接到百度
2.return false;
如果头部加入的是以下代码
<script type="text/javascript"> $(function() { $("#hr_three").click(function(event) { return false; }); }); <script>
再点击“点击我”,会弹出:我是最里层,但不会执行链接到百度页面
由此可以看出:
1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)
还有一种有冒泡有关的:
3.event.preventDefault();
如果把它放在头部A标签的click事件中,点击“点击我”。
会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)
细说 jQuery 事件篇(三) - 事件传播