DOM事件与事件委托

142 阅读3分钟

事件模型

浏览器的事件模型,就是通过监听函数对事件做出反应。事件发生后,浏览器监听到了这个时间,就会执行对应的监听函数。这是事件驱动编程模式(event-driven)的主要编程方式。
JavaScript有三种方法可以为事件绑定监听函数。

1.HTML的on-属性

HTML语言允许在元素的属性中,直接定义某些事件的监听代码

<body onload="doSomething()">
<div onclick="console.log('触发事件')">

但项目实践中我们不会这么写,因为违反了HTML与JavaScript代码相分离的原则。两者写在一起,不利于代码分工。

2.元素节点的事件属性

元素节点对象的事件属性,同样可以指定监听函数。

window.onload = doSomething;
div.onclick = function (event) {
  console.log('触发事件');
}

这种方法的缺陷在于:同一个事件只能定义一个监听函数,i.e.如果定义两次onclick属性,后一次定义会覆盖前一次。所以同样不建议使用。

3.EventTarget.addEventListener()

所有DOM节点实例都有addEventListener方法,用来为该节点定义事件的监听函数。

window.addEventListener('load', doSomething, false)  // 参数false指定在冒泡阶段监听事件

实践中推荐使用该方法,这种方法的优点在于:

  1. 同一个事件可以添加多个监听函数
  2. 能够指定在哪个阶段触发监听函数(捕获还是冒泡阶段)
  3. 除了DOM节点,其他对象(比如windowXMLHttpRequest等)也有这个接口,它等于是整个JavaScript统一的监听函数接口。

this的指向

三种方法监听函数内部的this指向触发事件的那个元素节点。
监听函数的两个属性:targetcurrentTarget有区别。

  1. e.target——指用户操作的元素
  2. e.currentTarget——指监听的元素,这也是this的指向 举例:
  • div > span{文字},用户点击文字
  • e.target就是span
  • e.currentTarget就是div

事件的传播

根据W3C在2002年发布的标准,浏览器应该同时支持两种调用顺序——先捕获,后冒泡。具体来说:

  • 第一阶段:从window对象传导到目标节点(上层传到底层,外层传到内层),定义为“捕获阶段”(capture phase)
  • 第二阶段:在目标节点上触发,称为“目标阶段”(target phase)
  • 第三阶段:从目标节点传导回window对象(从底层传回上层,从内层传到外层),成为“冒泡阶段”(bubbling phase)

事件委托

事件委托也叫做事件代理(delegation)。由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父结点上,由父节点的监听函数统一处理多个子元素的事件。这样做的好处是:

  • 节省内存
  • 同时也可以监听动态元素 如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。
// 事件传播到 p 元素后,就不再向下传播了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, true);

// 事件冒泡到 p 元素后,就不再向上冒泡了
p.addEventListener('click', function (event) {
  event.stopPropagation();
}, false);

需要注意stopPropagation方法只能阻止事件的传播,不能取消事件,如果想要彻底取消该事件,不再触发后面所有的监听函数,可以使用stopImmediatePropagation方法。

p.addEventListener('click', function (event) {
  event.stopPropagation();
  console.log(1);
});

p.addEventListener('click', function(event) {
  // 会触发
  console.log(2);
});
p.addEventListener('click', function (event) {
  event.stopImmediatePropagation();
  console.log(1);
});

p.addEventListener('click', function(event) {
  // 不会被触发
  console.log(2);
});

*资料来源:[网道教程](https://wangdoc.com/javascript/events/model.html)*