前言
笔记而已
事件流
事件流分为3个阶段,捕获,到达目标,冒泡。通常认为事件处理是冒泡行为的一部分。
document -> html -> body -> div(目标)-> body -> html -> document
事件处理
DOM0事件处理
为元素的事件处理属性赋值一个函数即可。事件处理程序会在元素的作用域中运行,所以事件处理程序的函数的this等于元素自身。使用DOM0事件处理,事件注册在事件流的冒泡阶段。
let btn = document.getElementById("myBtn");
btn.onclick = function() {
console.log(this.id); // "myBtn"
};
// 移除事件处理程序
btn.onclick = null
DOM2事件处理程序
这里红宝书有些不全,addEventListener, removeEventListener的第三个参数目前可以是一个配置项,也可以是一个布尔值。
addEventListener
addEventListener(事件名, 处理函数, options | useCapture,wantsUntrusted)。处理函数的this也是元素本身,addEventListener可以为一个元素添加多个事件处理程序。
通过addEventListener添加的事件处理程序,只能使用removeEventListener移除,addEventListener添加匿名函数无法被移除。
- options
- capture,是否在捕获阶段触发,默认为false(在冒泡阶段触发处理函数)
- once,是否只触发一次事件
- passive,事件处理程序不会调用
preventDefault
, 如果调用控制台会抛出警告
- wantsUntrusted 是否接受自定义事件
removeEventListener
removeEventListener(事件名, 处理函数, options | useCapture)
- options
- capture
- useCapture,是否移除捕获的事件监听器
事件对象
在事件发生的时候,所有相关信息都会存储在event对象中
event对象的属性和方法:
- type,事件的类型
- bubbles,是否可以事件冒泡
- cancelable,是否可以取消事件的默认行为
- 🌟 currentTarget,事件处理程序所在的元素,事件处理程序中
this === currentTarget
。 - 🌟 target,触发事件的元素。当事件是由添加处理事件程序的元素触发的时候, currentTarget和target相同
- defaultPrevented,是否调用过preventDefault方法
- eventPhase,事件处理程序的阶段,1-捕获阶段,2-到底目标,3-冒泡阶段,虽然事件处理程序是在冒泡阶段触发的,但是它的eventPhase仍然等于2。
- preventDefault(),取消事件默认行为,比如阻止a标签的链接导航
- stopPropagation(), 取消事件冒泡行为
- stopImmediatePropagation(), 如果一个元素添加了多个事件处理程序,调用stopImmediatePropagation会阻止后续事件处理程序的触发,并阻止冒泡。
事件类型
事件类型章节这块红宝书的作者罗列了很多事件,我在这里就不记录了。笔记,毕竟不是文档,对于api的东西还是现用现查。
合成事件
在输入中文的时候,需要多个键才能输入一个字符,合成事件用于检测这种输入
- compositionstart,正在输入还没有插入时触发
- compositionupdate,插入新字符时触发
- compositionend,输入关闭时触发
HTML5事件
- contextmenu,用户打开上下文菜单时触发
- beforeunload,页面即将卸载时触发
- DOMContentLoaded, DOM树构建完成后触发,而不会等待外部资源加载完成
性能
事件委托
利用事件冒泡,只使用一个事件处理程序,处理一组元素的一种类型的事件。最好的解决方案是只在document上设置事件处理程序。
// 可以只在ul元素上添加事件处理程序
<ul id="myLinks">
<li id="goSomewhere">Go somewhere</li>
<li id="doSomething">Do something</li>
<li id="sayHi">Say hi</li>
</ul>
let list = document.getElementById("myLinks");
list.addEventListener("click", (event) => {
let target = event.target;
switch(target.id) {
case "doSomething":
document.title = "I changed the document's title";
break;
case "goSomewhere":
location.href = "http:// www.wrox.com";
break;
case "sayHi":
console.log("hi");
break;
}
});
删除事件处理程序
使用innerHTML方法删除带有事件处理函数的元素,事件处理函数是不会被垃圾回收的。如果需要使用innerHTML替换元素,在这之前需要提前删除事件处理函数。
🚧 模拟事件
红宝书中关于模拟事件的内容很多都是过时的,比如initCustomEvent都已经废弃,可以使用CustomEvent替代