学习链接
事件模型-1
监听函数
HTML 的 on- 属性
<body onload="doSomething()"><div onclick="console.log('触发事件')">
注意,这些属性的值是将会执行的代码,而不是一个函数。
<!-- 正确 --><body onload="doSomething()"><!-- 错误 --><body onload="doSomething">
只会在冒泡阶段触发。
元素节点的事件属性
window.onload = doSomething;div.onclick = function (event) {console.log('触发事件');};
属性的值是将一个函数,而不是会执行的代码。
只会在冒泡阶段触发。
EventTarget.addEventListener()
EventTarget.addEventListener()
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,接着依次是document,html(document.documentElement)和body(document.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**事件无冒泡阶段
