DOM 事件机制与事件委托

413 阅读3分钟

问题:

如果一个元素拥有祖先元素,在这个元素上添加一个click,然后在页面上点击这个函数,那么是这个元素还是他的祖先元素上的事件先被触发呢? 例:

<div id="click1">
  <div id="click2">
  </div>
</div>

以上就需要了解到事件冒泡与事件捕获的知识来加以判断

什么是事件冒泡与事件捕获

事件冒泡

事件冒泡是IE的开发团队提出的,它定义了事件首先由最具体的元素接收,然后逐级冒泡到上级元素。也就是说函数监听是从儿子——爸爸——爷爷的顺序进行监听

事件捕获

事件捕获是网景开发团队提出的,它定义了事件先由具体元素的最上级接收,然后逐级捕获到具体元素。可以理解为与事件冒泡相反,从爷爷——爸爸——儿子的顺序进行函数监听

注意:主流浏览器都支持这两种事件,但由于老版本的浏览器不支持事件捕获,所以还是事件冒泡更受开发者欢迎

捕获与冒泡的标准

在之前最黑暗的年代,IE与网景各持己见,都认为自己的方法才应该是标准,以至于最后W3C出面,制定了最终的事件机制标准。 W3C标准则取其折中方案. W3C事件模型中发生的任何事件, 先从其祖先元素开始一路向下捕获, 直到达到目标元素, 其后再次从目标元素开始冒泡.

图例:

事件绑定

那么我们可不可以通过代码来控制事件到底是按照捕获还是冒泡呢?

答:w3c提供了一个API :addEventListener来控制事件。这个方法这个需要输入三个参数。第一个参数是要挂载的事件,比如click;第二个参数输入的是发生事件对应的函数,比如点击跳转页面;第三个参数输入的是一个布尔类型,当输入为false时,则处理事件按照事件冒泡顺序;若输入为true,则处理事件按照事件捕获顺序。第三个参数的默认值为false。(由此可以看出W3C还是更偏爱IE的方法的)

例:

e.addEventLisenter('click',f2,true) // 按照捕获方向执行
e.addEventLisenter('click',f2,false) // 按照冒泡方向执行

以下是MDN对此的官方说明:

EventTarget.addEventListener(event, function, useCapture)方法将指定的监听器注册到 EventTarget 上,当该对象触发指定的事件时,指定的回调函数就会被执行。

特殊情况

如果被点击的元素既有捕获阶段又有冒泡阶段,那么最终的执行顺序是书写的顺序去执行

阻止(取消)事件进行

首先捕获是无法阻止的,因为目标元素是DOM树中的根,这个根是一定要存在的

取消冒泡事件

在需要取消的地方加入e.stopPropagation()可以中断冒泡,意思是告诉后面的元素糖葫芦到我这卖完了,没你们啥事了

事件委托

事件委托指的是:当监听子元素时,利用事件冒泡,使得目标元素向上传递到父级直到document,如果子元素不确定或者动态生成,可以通过监听父元素来取代监听子元素。(通俗来讲就是你的快递放到了存放点,然后存放点给你发消息告诉你快递来了)

事件委托的优点:

  1. 减少内存消耗,减少事件绑定

  2. 给动态添加的元素绑定事件

缺点:

  1. 部分事件如 focus、blur 等无冒泡机制,所以无法委托。
  2. 事件委托有对子元素的查找过程,委托层级过深,可能会被某一层阻止掉
  3. 频繁触发的事件,不适合事件委托