事件委托

在了解事件委托之前,我们首先要知道浏览器规定的概念:

DOM2 级事件规定的事件流包括三个阶段:事件捕获目标阶段事件冒泡

  • 事件流:描述的是从页面中接收事件的顺序
  • 事件冒泡:事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点或文档。
  • 事件捕获:事件开始由不太具体的节点接收,然后逐级向下传播到最具体的节点。它与事件冒泡是相反的过程

事件流

click 事件发生的顺序 :

1
2
3
4
5
<ul id="myLink">
<li id="1">aaa</li>
<li id="2">bbb</li>
<li id="3">ccc</li>
</ul>

事件冒泡 li -> ul -> body -> html -> document ->window

事件捕获 window -> document-> html -> body -> ul ->li

事件委托概念

通俗的说就是将元素的事件委托给它的父级或者更外级的元素处理,它的实现机制就是事件冒泡

不使用事件委托

1
2
3
4
5
6
7
8
9
10
var myLink = document.getElementById("myLink");
var li = myLink.getElementsByTagName("li");

for (var i = 0; i < li.length; i++) {
li[i].onclick = function (e) {
var e = event || window.event;
var target = e.target || e.srcElement;
alert(e.target.id + ":" + e.target.innerText);
};
}
  • 给每一个列表都绑定事件,消耗内存
  • 当有动态添加的元素时,需要重新给元素绑定事件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
function delegate(element, eventType, selector, fn) {
element.addEventListener(eventType, (e) => {
let el = e.target;
while (!el.matches(selector)) {
if (element === el) {
el = null;
break;
}
el = el.parentNode;
}
el && fn.call(el, e, el);
});
return element;
}

事件委托的优点

  • 只需要将同类元素的事件委托给父级或者更外级的元素,不需要给所有的元素都绑定事件减少内存占用空间,提升性能。
  • 动态新增的元素无需重新绑定事件

事件委托的实现依靠的冒泡,因此不支持事件冒泡的事件就不适合使用事件委托。

不是所有的事件绑定都适合使用事件委托,不恰当使用反而可能导致不需要绑定事件的元素也被绑定上了事件。

addEventListener 监听器方法第三个参数

1
element.addEventListener(event, function, useCapture)

useCapture
可选。布尔值,指定事件是否在捕获或冒泡阶段执行。

可能值:

  • true - 事件句柄在捕获阶段执行(即在事件捕获阶段调用处理函数)
  • false- 默认。事件句柄在冒泡阶段执行(即表示在事件冒泡的阶段调用事件处理函数)

(1)toLowerCase() 方法用于把字符串转换为小写。语法:stringObject.toLowerCase()返回值:一个新的字符串,在其中 stringObject 的所有大写字符全部被转换为了小写字符。

(2)nodeName 属性指定节点的节点名称。如果节点是元素节点,则 nodeName 属性返回标签名。如果节点是属性节点,则 nodeName 属性返回属性的名称。对于其他节点类型,nodeName 属性返回不同节点类型的不同名称。所有主流浏览器均支持 nodeName 属性。

阻止事件冒泡

  1. 给子级加 event.stopPropagation( )
1
2
3
4
$("#div1").mousedown(function (e) {
var e = event || window.event;
event.stopPropagation();
});
  1. 在事件处理函数中返回 false
1
2
3
4
$("#div1").mousedown(function (event) {
var e = e || window.event;
return false;
});

但是这两种方式是有区别的。return false 不仅阻止了事件往上冒泡,而且阻止了事件本身(默认事件)。event.stopPropagation()则只阻止事件往上冒泡,不阻止事件本身。

  1. event.target==event.currentTarget,让触发事件的元素等于绑定事件的元素,也可以阻止事件冒泡;

event.currentTarget 告诉我们该事件附加在哪个元素上,或者其 eventListener 触发了该事件的元素。
event.target 告诉事件从哪里开始。

给父节点绑定事件做冒泡的事件代理的原因是:evt.target 永远拿到的都是最深层的目标节点,在点击节点的时候,由于冒泡的原因,触发了父节点的点击事件,这个时候可以通过 evt.target 拿到真正点击的深层子节点,然后做进一步逻辑

注意点

  1. 事件流顺序
  2. 事件委托原理->事件冒泡的应用
  3. addEventListener 第三个参数 默认是 false 事件冒泡时触发 true 为事件捕获阶段触发
  4. e.target 和 e.currentTarget 的区别