2

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 可能出现的问题来解决的,对于事件冒泡可能导致的其他弊端现象,我们需要用更加适用的方法来解决,因为这个知识点在书中的下一个章节介绍,所以我打算在下一篇博文中总结。

参考

http://book.douban.com/subject/24669823/


StephenLi
7k 声望488 粉丝

知不足。