细说 jQuery - 事件传播



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 事件篇(三) - 事件传播



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值