学习链接

事件模型

事件模型-1

监听函数

HTML 的 on- 属性

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

注意,这些属性的值是将会执行的代码,而不是一个函数

  1. <!-- 正确 -->
  2. <body onload="doSomething()">
  3. <!-- 错误 -->
  4. <body onload="doSomething">

只会在冒泡阶段触发。

元素节点的事件属性

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

属性的值是将一个函数,而不是会执行的代码

只会在冒泡阶段触发。

EventTarget.addEventListener()

EventTarget.addEventListener()

  1. target.addEventListener(type, listener[, useCapture]);

该方法接受三个参数。

  • type:事件名称,大小写敏感。
  • listener:监听函数。可为具有 **handleEvent()** 方法的对象
  • useCapture:布尔值,如果设为 **true**,表示监听函数将在捕获阶段(capture)触发。
    该参数可选,默认值为 **false**(监听函数只在冒泡阶段被触发)。

如果为同一个事件多次添加同一个监听函数,该函数只会执行一次,多余的添加将自动被去除

(不必使用removeEventListener()方法手动去除)。

第三个参数不同,会被视为不同的监听函数。

即在一个对象上的不同阶段绑定了同一个监听函数,会被视为不同的监听函数,触发两次

三者对比

  • HTML 的 on- 属性
    违反了 HTML 与 JavaScript 代码相分离的原则。
  • 元素节点的事件属性
    同一个事件只能定义一个监听函数。
    也就是说,如果定义两次onclick属性,后一次定义会覆盖前一次。
  • EventTarget.addEventListener() 👍
    • 同一事件可添加多个监听函数
    • 可指定触发监听函数的阶段(捕获阶段或者冒泡阶段

事件的传播

一个事件发生后,会在子元素和父元素之间传播(propagation)。这种传播分成三个阶段。

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

事件传播的最上层对象是window,接着依次是documenthtmldocument.documentElement)和bodydocument.body),逐层到达目标节点。

监听函数的 this 指向

若参数 listener普通函数,则 this 指向触发事件的节点。

若参数 listener箭头函数,则 this 一般指向 window

若参数 listener具有 **handleEvent()** 方法的对象,则 this 指向该对象。

Event.currentTarget,Event.target

  • event.target:原始触发事件的节点,不会随着事件的传播而改变。
  • event.currentTarget绑定事件监听函数的节点,即事件当前所在的节点,会随着事件的传播而改变。
    是回调函数为普通函数的 this 指向。

事件的代理 / 委托

由于事件会在冒泡阶段向上传播到父节点,因此可以把子节点的监听函数定义在父节点上

父节点的监听函数统一处理多个子元素的事件。这种方法叫做事件的代理(delegation)。

  • 节省内存,减少 DOM 操作,提高性能
  • 不需要给子节点注销事件
  • 动态绑定事件

如果希望事件到某个节点为止,不再传播,可以使用事件对象的stopPropagation方法。

但是,stopPropagation方法只会阻止事件的传播,不会阻止该事件触发<p>节点的其他click事件的监听函数。也就是说,不是彻底取消该事件的监听。

如果想要彻底取消该事件,不再触发后面所有该事件的监听函数,可以使用stopImmediatePropagation方法。

特殊事件

所有事件都要经过捕获阶段和处于目标阶段,但有些事件没有冒泡阶段。

  • **mouseover**:鼠标经过自身盒子会触发,经过子盒子还会触发。
  • **mouseenter**:只会经过自身盒子触发。
    • **mouseenter****mouseleave** 无冒泡阶段
  • **focus****blur** 事件无冒泡阶段