JavaScript事件说明

浏览器中的JavaScript使用事件驱动的编程模型。一切都始于事件。这是对JavaScript事件的介绍,以及事件处理的工作方式

介绍

浏览器中的JavaScript使用事件驱动的编程模型。

一切都始于事件。

该事件可能是DOM加载,完成获取的异步请求,用户单击元素或滚动页面或用户在键盘上键入。

有很多不同类型的事件。

事件处理程序

您可以使用事件处理程序,这是事件发生时调用的函数。

您可以为同一事件注册多个处理程序,并且在该事件发生时将全部调用它们。

JavaScript提供了三种注册事件处理程序的方式:

内联事件处理程序

由于其约束,今天很少使用这种事件处理程序样式,但这是JavaScript早期的唯一方法:

<a href="site.com" onclick="dosomething();">A link</a>

DOM事件处理程序

当一个对象最多具有一个事件处理程序时,这是很常见的,因为在这种情况下无法添加多个处理程序:

window.onload = () => {
  //window loaded
}

在处理时最常用XHR要求:

const xhr = new XMLHttpRequest()
xhr.onreadystatechange = () => {
  //.. do something
}

您可以使用以下方法检查处理程序是否已分配给属性if ('onsomething' in window) {}

使用addEventListener()

这是现代方式。此方法允许注册所需数量的处理程序,并且它是最受欢迎的处理程序:

window.addEventListener('load', () => {
  //window loaded
})

请注意,IE8和更低版本不支持此功能,而是使用了它自己的attachEvent()API。如果您需要支持较旧的浏览器,请记住这一点。

聆听不同的元素

你可以听window拦截“全局”事件(例如键盘的用法),您可以侦听特定元素以检查事件的发生,例如鼠标单击按钮。

这就是为什么addEventListener有时会被调用window,有时在DOM元素上。

事件对象

一个事件处理程序得到一个Event对象作为第一个参数:

const link = document.getElementById('my-link')
link.addEventListener('click', event => {
  // link clicked
})

该对象包含许多有用的属性和方法,例如:

  • target,是引发事件的DOM元素
  • type,事件类型
  • stopPropagation(),称为停止在DOM中传播事件

查看完整清单)。

其他属性由特定类型的事件提供,例如Event是用于不同特定事件的接口:

每个页面都有一个链接的MDN页面,因此您可以检查它们的所有属性。

例如,当发生KeyboardEvent时,您可以以可读格式检查按下了哪个键(EscapeEnter依此类推)key财产:

window.addEventListener('keydown', event => {
  // key pressed
  console.log(event.key)
})

在发生鼠标事件时,我们可以检查按下了哪个鼠标按钮:

const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
  // mouse button pressed
  console.log(event.button) //0=left, 2=right
})

事件冒泡和事件捕获

冒泡和捕获是事件用于传播的两个模型。

假设您的DOM结构是

<div id="container">
  <button>Click me</button>
</div>

您想跟踪用户何时单击按钮,并且有2个事件侦听器,其中一个button和一个#container。请记住,单击子元素将始终传播到其父元素,除非您停止传播(请参阅下文)。

这些事件侦听器将按顺序调用,此顺序由所使用的事件冒泡/捕获模型确定。

起泡表示事件从被单击的项(子项)一直传播到其所有父树,从最近的树开始。

在我们的示例中,button会在#container处理程序。

捕捉相反:外部事件处理程序在更具体的处理程序之前触发,button

默认情况下,所有事件都会冒泡

您可以通过将第三个参数应用于addEventListener并将其设置为来选择采用事件捕获true

document.getElementById('container').addEventListener(
  'click',
  () => {
    //window loaded
  },
  true
)

注意首先运行所有捕获事件处理程序

然后是所有冒泡事件处理程序。

顺序遵循此原则:DOM从Window对象开始遍历所有元素,然后查找被单击的项目。这样做时,它将调用与事件关联的任何事件处理程序(捕获阶段)。

一旦到达目标,它就会重复遍历父树的过程,直到Window对象,再次调用事件处理程序(冒泡阶段)。

停止传播

除非停止,否则DOM元素上的事件将传播到其所有父元素树。

<html>
  <body>
    <section>
      <a id="my-link" ...>

的点击事件a将传播到section接着body

您可以通过调用stopPropagation()Event的方法,通常在事件处理程序的末尾:

const link = document.getElementById('my-link')
link.addEventListener('mousedown', event => {
  // process the event
  // ...

  event.stopPropagation()
})

以下是您可能会处理的最常见事件的列表。

加载

load被开除windowbody页面加载完成后的元素。

鼠标事件

click单击鼠标按钮时触发。dblclick两次单击鼠标时。当然在这种情况下click在此事件之前被解雇。mousedownmousemovemouseup可以组合使用以跟踪拖放事件。小心mousemove,因为它在鼠标移动过程中会多次触发(请参见节流之后)

键盘事件

keydown按下键盘按钮时触发(以及在按钮按下时重复按键的任何时间)停留按下)。keyup释放键时触发。

滚动

scroll事件被触发window每次滚动页面。在事件处理程序内,您可以通过检查以下内容来检查当前滚动位置window.scrollY

请记住,此事件不是一次性事件。它在滚动过程中会触发很多次,而不仅仅是在滚动结束或开始时,所以不要在处理程序中进行任何繁重的计算或操作-使用节流反而。

节流

如上所述,mousemovescroll有两个事件不会在每个事件中一次性触发,而是在动作的所有持续时间内连续调用它们的事件处理函数。

这是因为它们提供了坐标,因此您可以跟踪正在发生的事情。

如果在事件处理程序中执行复杂的操作,则会影响性能并给站点用户带来缓慢的体验。

提供节流功能的库洛达什用100多行代码实施它,以处理所有可能的用例。这是一个简单易懂的实现,它使用setTimeout每100毫秒缓存一次滚动事件:

let cached = null
window.addEventListener('scroll', event => {
  if (!cached) {
    setTimeout(() => {
      //you can access the original event at `cached`
      cached = null
    }, 100)
  }
  cached = event
})

免费下载我的JavaScript初学者手册


更多js教程: