「读书笔记」第四版JavaScript高级程序设计(第十七章)

321 阅读3分钟

前言

笔记而已

事件流

事件流分为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替代

参考