js 事件参考

news2024/11/18 3:34:38

事件参考

事件介绍

触发事件是为了通知代码可能影响代码执行的“有趣变化”。这些可能来自用户交互,例如使用鼠标或调整窗口大小,底层环境状态的变化(例如,低电量或来自操作系统的媒体事件)以及其他原因。

每个事件都由一个基于Event接口的对象表示,并且可能有额外的自定义字段和/或函数来提供关于发生的事情的信息。每个事件的文档都有一个表(靠近顶部),其中包括到相关事件接口的链接以及其他相关信息。 Event > Interfaces based on Event中给出了不同事件类型的完整列表。

本主题提供了您可能感兴趣的主要类型事件(动画,剪贴板,workers 等)的索引以及实现这些类型事件的主要类。最后是所有记录事件的扁平列表。

注意:本页列出了许多你在网上会遇到的最常见的事件。如果您正在搜索此处未列出的事件,请尝试在MDN的其余部分搜索其名称、主题区域或相关规范。

Event index

Event listing
本节列出了在MDN上有自己参考页面的事件。如果您对此处未列出的事件感兴趣,请尝试在MDN的其余部分搜索其名称、主题领域或相关规范。

1、创建和触发事件

本文演示了如何创建和分派DOM事件。这些事件通常被称为合成事件(synthetic events),与浏览器本身触发的事件相反。

1.1 创建自定义事件

事件可以用Event构造函数创建,如下所示:

const event = new Event("build");

// Listen for the event.
elem.addEventListener(
  "build",
  (e) => {
    /* … */
  },
  false,
);

// Dispatch the event.
elem.dispatchEvent(event);

上面的代码示例使用了EventTarget.dispatchEvent()方法。

大多数现代浏览器都支持此构造函数。要了解更详细的方法,请参见下面的老式方法。

添加自定义数据- CustomEvent()

要向事件对象添加更多数据,存在CustomEvent接口,并且可以使用detail属性来传递自定义数据。例如,可以这样创建事件:

const event = new CustomEvent("build", { detail: elem.dataset.time });

这将允许您访问事件监听器中的其他数据:

function eventHandler(e) {
  console.log(`The time is: ${e.detail}`);
}

老式的方式

创建事件的旧方法使用受Java启发的api。下面是一个使用document.createEvent()的示例:

// Create the event.
const event = document.createEvent("Event");

// Define that the event name is 'build'.
event.initEvent("build", true, true);

// Listen for the event.
elem.addEventListener(
  "build",
  (e) => {
    // e.target matches elem
  },
  false,
);

// target can be any Element or other EventTarget.
elem.dispatchEvent(event);

事件冒泡

通常希望从子元素触发事件,并让一个祖先捕获它;可选的,带数据:

<form>
  <textarea></textarea>
</form>
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

// Create a new event, allow bubbling, and provide any data you want to pass to the "detail" property
const eventAwesome = new CustomEvent("awesome", {
  bubbles: true,
  detail: { text: () => textarea.value },
});

// The form element listens for the custom "awesome" event and then consoles the output of the passed text() method
form.addEventListener("awesome", (e) => console.log(e.detail.text()));

// As the user types, the textarea inside the form dispatches/triggers the event to fire, and uses itself as the starting point
textarea.addEventListener("input", (e) => e.target.dispatchEvent(eventAwesome));

动态创建和调度事件

元素可以监听尚未创建的事件:

<form>
  <textarea></textarea>
</form>
const form = document.querySelector("form");
const textarea = document.querySelector("textarea");

form.addEventListener("awesome", (e) => console.log(e.detail.text()));

textarea.addEventListener("input", function () {
  // Create and dispatch/trigger an event on the fly
  // Note: Optionally, we've also leveraged the "function expression" (instead of the "arrow function expression") so "this" will represent the element
  this.dispatchEvent(
    new CustomEvent("awesome", {
      bubbles: true,
      detail: { text: () => textarea.value },
    }),
  );
});

1.2 触发内置事件

这个示例演示了使用DOM方法模拟复选框上的单击(以编程方式生成单击事件)。查看实际示例

function simulateClick() {
  const event = new MouseEvent("click", {
    view: window,
    bubbles: true,
    cancelable: true,
  });
  const cb = document.getElementById("checkbox");
  const cancelled = !cb.dispatchEvent(event);

  if (cancelled) {
    // A handler called preventDefault.
    alert("cancelled");
  } else {
    // None of the handlers called preventDefault.
    alert("not cancelled");
  }
}

2、事件处理(概述)

事件是在浏览器窗口内触发的信号,用于通知浏览器或操作系统环境中的更改。程序员可以创建在事件触发时运行的事件处理程序(event handler)代码,从而允许网页对变化做出适当的响应。

本页提供了一个关于如何使用事件和事件处理程序的非常简短的“提醒”。新开发者应该阅读事件简介。

2.1 可用的事件有哪些?

事件记录在发出事件的JavaScript对象的页面中或页面下方。例如,要查找浏览器窗口或当前文档上触发的事件,请参阅“窗口”和“文档”中的“事件”部分。

你可以使用 Event 参考来查找哪些JavaScript对象为特定的 APIs 触发事件,例如动画、媒体等等。

2.2 注册事件处理程序

有两种推荐的方法来注册处理程序。事件处理程序代码可以在触发事件时运行,方法是将其分配给目标元素对应的onevent属性,或者使用addEventListener()方法将处理程序注册为元素的监听器。在任何一种情况下,处理程序都将接收一个符合Event接口(或派生接口)的对象。主要区别在于可以使用事件监听器方法添加(或删除)多个事件处理程序。

警告:不推荐使用HTML onevent属性设置事件处理程序的第三种方法!它们使标记膨胀,使其可读性降低,更难调试。有关更多信息,请参阅内联事件处理程序。

2.2.1 使用 onevent 属性

按照约定,触发事件的JavaScript对象具有相应的“onevent”属性(通过在事件名称前加上前缀“on”来命名)。在触发事件时调用这些属性以运行相关的处理程序代码,也可以由您自己的代码直接调用这些属性。

要设置事件处理程序代码,只需将其分配给适当的onevent属性元素中的每个事件只能分配一个事件处理程序。如果需要,可以通过将另一个函数分配给同一属性来替换处理程序。

下面我们将展示如何使用onclick属性为click事件设置一个简单的greet()函数。

const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.onclick = greet;

**请注意,将表示事件的对象作为第一个参数传递给事件处理程序。**此事件对象实现Event接口或从Event接口派生。

2.2.2 EventTarget.addEventListener

在元素上设置事件处理程序的最灵活的方法是使用EventTarget.addEventListener方法。这种方法允许将多个监听器分配给一个元素,并在需要时删除侦听器(使用EventTarget.removeEventListener)。

注意:添加和删除事件处理程序的功能允许您,例如,让相同的按钮在不同的情况下执行不同的操作。此外,在更复杂的程序中,清理旧的/未使用的事件处理程序可以提高效率。

下面我们将展示如何将一个简单的greet()函数设置为click事件的监听器/事件处理程序(如果需要,可以使用lambda函数而不是命名函数)。再次注意,事件作为第一个参数传递给事件处理程序。

const btn = document.querySelector("button");

function greet(event) {
  console.log("greet:", event);
}

btn.addEventListener("click", greet);

该方法还可以使用其他参数/选项来控制捕获和删除事件的方式。更多信息可以在EventTarget.addEventListener引用页上找到。

2.2.3 使用中止信号

一个值得注意的事件监听器特性是能够使用中止信号同时清理多个事件处理程序。

这是通过将相同的AbortSignal传递给您希望能够一起删除的所有事件处理程序的addEventListener()调用来完成的。然后,您可以在拥有AbortSignal的控制器上调用abort(),它将删除与该信号一起添加的所有事件处理程序。例如,要添加一个可以用AbortSignal删除的事件处理程序:

const controller = new AbortController();

btn.addEventListener(
  "click",
  (event) => {
    console.log("greet:", event);
  },
  { signal: controller.signal },
); // pass an AbortSignal to this handler

然后,上面代码创建的事件处理程序可以像这样删除:

controller.abort(); // removes any/all event handlers associated with this controller

3、 js 构建块(事件介绍)

事件是在您正在编程的系统中发生的事情,系统会告诉您有关这些事件的信息,以便您的代码能够对它们做出反应。

例如,如果用户单击网页上的一个按钮,您可能希望通过显示一个信息框来对该操作作出反应。在本文中,我们将讨论与事件相关的一些重要概念,并研究它们在浏览器中的工作方式。这不会是一个详尽的研究;这就是你现在需要知道的。

3.1 什么是事件?

事件是在您正在编程的系统中发生的事情—当事件发生时,系统产生(或“触发”,produces (or “fires”))某种类型的信号,并提供一种机制,通过该机制,可以在事件发生时自动采取操作(即运行某些代码)。事件在浏览器窗口内触发,并且倾向于附加到驻留在其中的特定项。这可能是单个元素、一组元素、当前选项卡中加载的HTML文档或整个浏览器窗口。可能发生许多不同类型的事件。

例如:

  • 用户选择、单击或将光标悬停在某个元素上。
  • 用户在键盘上选择一个键。
  • 用户调整或关闭浏览器窗口。
  • 网页加载完成。
  • 提交表单。
  • 视频开始播放、暂停或结束。
  • 出现错误。

您可以从这里(以及浏览MDN事件引用)了解到,有很多事件可以被触发。

要对事件作出反应,需要将事件处理程序(event handler)附加到事件上。这是在事件触发时运行的代码块(通常是程序员创建的JavaScript函数)。当这样的代码块被定义为响应一个事件而运行时,我们说我们正在注册一个事件处理程序( registering an event handler)。注意:事件处理程序有时被称为事件监听器(event listeners)——它们在我们的目的中几乎是可互换的,尽管严格地说,它们是一起工作的。监听器监听事件的发生,处理程序是响应事件发生而运行的代码。

注意:Web事件不是JavaScript核心语言的一部分——它们被定义为浏览器内置APIs 的一部分。

示例:处理单击事件

在下面的例子中,我们在页面中只有一个<button>:

<button>Change color</button>

然后我们有一些JavaScript。我们将在下一节中更详细地讨论这个问题,但现在我们只能说:它为按钮的“click”事件添加了一个事件处理程序,并且处理程序通过将页面背景设置为随机颜色来响应事件:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

btn.addEventListener("click", () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});

示例输出如下。试着点击这个按钮:
在这里插入图片描述

3.2 使用addEventListener ()

正如我们在上一个示例中看到的,可以触发事件的对象有一个addEventListener()方法,这是添加事件处理程序的推荐机制。

让我们仔细看看最后一个例子中的代码:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

btn.addEventListener("click", () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
});

当用户单击按钮时,HTML <button>元素将触发一个事件。所以它定义了一个addEventListener()函数,我们在这里调用它。我们传入两个参数:

  • 字符串"click",表示我们想要监听click事件。按钮可以触发许多其他事件,例如当用户将鼠标移动到按钮上时发生"mouseover",或者当用户按下一个键并且按钮定焦时发生“keydown”。
  • 当事件发生时调用的函数。在我们的示例中,该函数生成一个随机的RGB颜色,并将页面<body>的背景色background-color设置为该颜色。

让handler函数成为一个单独的命名函数是可以的,像这样:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

function changeBackground() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

btn.addEventListener("click", changeBackground);

监听其他事件

一个按钮元素可以触发许多不同的事件。继续我们的实验。

首先,在本地复制random-color-addeventlistener.html,并在浏览器中打开它。这只是一个简单的随机颜色的例子的复制,我们已经玩过了。现在尝试依次将click更改为以下不同的值,并观察示例中的结果:

  • focus and blur -当按钮聚焦和未聚焦时,颜色会发生变化;尝试按TAB键聚焦在按钮上,然后再按TAB键将焦点从按钮移开。这些通常用于在表单字段聚焦时显示有关填充表单字段的信息,或者在表单字段填充了不正确的值时显示错误消息。
  • dblclick 只有双击按钮时颜色才会改变。
  • mouseover and mouseout 当鼠标指针悬停在按钮上或指针离开按钮时,颜色分别发生变化。

有些事件(如click)几乎可以在任何元素上使用。另一些则更具体,只在某些情况下有用:例如,play事件只对某些元素可用,如<video>

删除监听器

如果您使用addEventListener()添加了一个事件处理程序,您可以使用removeEventListener()方法再次删除它。例如,这将删除changeBackground()事件处理程序:

btn.removeEventListener("click", changeBackground);

事件处理程序也可以通过将AbortSignal传递给addEventListener(),然后在拥有AbortSignal的控制器上调用abort()来删除。例如,要添加一个可以用AbortSignal删除的事件处理程序:

const controller = new AbortController();

btn.addEventListener("click",
  () => {
    const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
    document.body.style.backgroundColor = rndCol;
  },
  { signal: controller.signal } // pass an AbortSignal to this handler
);

然后,上面代码创建的事件处理程序可以像这样删除:

controller.abort(); // removes any/all event handlers associated with this controller

对于简单的小程序,清理旧的、未使用的事件处理程序是没有必要的,但是对于更大、更复杂的程序,它可以提高效率。此外,删除事件处理程序的功能允许您让相同的按钮在不同的情况下执行不同的操作:您所要做的就是添加或删除处理程序。

为单个事件添加多个监听器

通过对addEventListener()进行多个调用,提供不同的处理程序,您可以为单个事件提供多个处理程序:

myElement.addEventListener("click", functionA);
myElement.addEventListener("click", functionB);

现在,当单击元素时,这两个函数都将运行。

Learn more

addEventListener()还有其他强大的特性和选项可用。

这些内容超出了本文的范围,但是如果您想阅读它们,请访问addEventListener()和removeEventListener()参考页面。

3.3 其他事件监听器机制

我们建议您使用addEventListener()来注册事件处理程序。它是最强大的方法,适用于更复杂的程序。但是,您可能还会看到另外两种注册事件处理程序的方式:事件处理程序属性(event handler properties)和内联事件处理程序(inline event handlers)。

事件处理程序属性

可以触发事件的对象(如按钮)通常也具有名称为on的属性,后面跟着事件名称。例如,元素有一个onclick属性。这称为事件处理程序属性。要监听事件,可以将处理函数分配给属性。

例如,我们可以这样重写随机颜色的例子:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

btn.onclick = () => {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
};

你也可以将handler属性设置为一个命名函数:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

btn.onclick = bgChange;

使用事件处理程序属性,您不能为单个事件添加多个处理程序。例如,你可以在一个元素上多次调用addEventListener('click', handler),并在第二个参数中指定不同的函数:

element.addEventListener("click", function1);
element.addEventListener("click", function2);

这对于事件处理程序属性是不可能的,因为任何后续尝试设置该属性都会覆盖先前的属性:

element.onclick = function1;
element.onclick = function2;

内联事件处理程序——不要使用这些

你可能也会在你的代码中看到这样的模式:

<button onclick="bgChange()">Press me</button>
function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  document.body.style.backgroundColor = rndCol;
}

在Web上注册事件处理程序的最早方法涉及事件处理程序HTML属性(或内联事件处理程序),如上面所示—属性值实际上是您希望在事件发生时运行的JavaScript代码。上面的例子调用了在同一页面的<script>元素中定义的函数,但是你也可以直接在属性中插入JavaScript,例如:

<button onclick="alert('Hello, this is my old-fashioned event handler!');">
  Press me
</button>

你可以找到许多事件处理程序属性的对等HTML属性;然而,你不应该使用这些——它们被认为是不好的做法。如果您正在快速执行某些操作,那么使用事件处理程序属性似乎很容易,但是它们很快就会变得难以管理且效率低下。

首先,将HTML和JavaScript混在一起并不是一个好主意,因为这会变得难以阅读。保持JavaScript独立是一种很好的做法,如果它位于单独的文件中,则可以将其应用于多个HTML文档。

即使在单个文件中,内联事件处理程序也不是一个好主意。一个按钮是可以的,但是如果你有100个按钮呢?你必须在文件中添加100个属性;它很快就会变成一场维修噩梦。使用JavaScript,你可以很容易地为页面上的所有按钮添加事件处理函数,无论有多少按钮,使用如下代码:

const buttons = document.querySelectorAll("button");

for (const button of buttons) {
  button.addEventListener("click", bgChange);
}

最后,作为一种安全措施,许多常见的服务器配置将不允许内联JavaScript。

永远不要使用HTML事件处理程序属性——这些属性已经过时了,使用它们是不好的做法。

3.4 Event 对象

有时,在事件处理程序函数中,您会看到一个指定了名称的参数,如eventevte。这称为事件对象(event object),它被自动传递给事件处理程序,以提供额外的功能和信息。例如,让我们再重写一下随机颜色的例子:

const btn = document.querySelector("button");

function random(number) {
  return Math.floor(Math.random() * (number + 1));
}

function bgChange(e) {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  e.target.style.backgroundColor = rndCol;
  console.log(e);
}

btn.addEventListener("click", bgChange);

注意:你可以在GitHub上找到这个例子的完整源代码。

在这里,你可以看到我们在函数中包含了一个事件对象e,并在函数中为e.target(即按钮本身)设置了背景颜色样式。事件对象的target 属性始终是对发生事件的元素的引用。因此,在这个例子中,我们在按钮上设置一个随机的背景颜色,而不是页面。

注意:请参阅下面的事件委托部分,以获取我们使用event.target的示例。

注意:您可以为事件对象使用任何您喜欢的名称—您只需要选择一个您可以在事件处理程序函数中引用它的名称。e /evt/event最常被开发人员使用,因为它们简短且易于记忆。保持一致总是好的——对自己,如果可能的话对别人。

事件对象的额外属性

大多数事件对象在事件对象上都有一组标准的属性和方法;有关完整列表,请参阅Event对象参考。

一些事件对象添加了与特定类型的事件相关的额外属性。例如,当用户按下一个键时触发keydown事件。它的事件对象是一个KeyboardEvent,它是一个特殊的事件对象,带有一个key属性,告诉你按下了哪个键:

<input id="textBox" type="text" />
<div id="output"></div>
const textBox = document.querySelector("#textBox");
const output = document.querySelector("#output");
textBox.addEventListener("keydown", (event) => {
  output.textContent = `You pressed "${event.key}".`;
});

3.5 防止默认行为

有时,您会遇到这样一种情况:您希望阻止事件执行其默认执行的操作。最常见的例子是web表单,例如自定义注册表单。当您填写详细信息并单击提交按钮时,自然的行为是将数据提交到服务器上的指定页面进行处理,并将浏览器重定向到某种“成功消息”页面(如果未指定另一个页面,则为同一页面)。

当用户没有正确提交数据时,麻烦就来了——作为开发人员,您希望阻止向服务器提交数据,并给出一个错误消息,说明哪里出错了,需要做些什么来纠正错误。有些浏览器支持自动表单数据验证功能,但由于许多浏览器不支持,因此建议您不要依赖这些功能,而是实现自己的验证检查。让我们看一个简单的例子。

首先是一个简单的HTML表单,它需要你输入你的姓和名:

<form>
  <div>
    <label for="fname">First name: </label>
    <input id="fname" type="text" />
  </div>
  <div>
    <label for="lname">Last name: </label>
    <input id="lname" type="text" />
  </div>
  <div>
    <input id="submit" type="submit" />
  </div>
</form>
<p></p>

现在是一些JavaScript——这里我们在submit事件的处理程序中实现了一个非常简单的检查(提交事件在表单提交时触发),测试文本字段是否为空。如果是,我们调用事件对象上的preventDefault()函数——它会停止表单提交——然后在表单下面的段落中显示一个错误消息,告诉用户哪里出错了:

const form = document.querySelector("form");
const fname = document.getElementById("fname");
const lname = document.getElementById("lname");
const para = document.querySelector("p");

form.addEventListener("submit", (e) => {
  if (fname.value === "" || lname.value === "") {
    e.preventDefault();
    para.textContent = "You need to fill in both names!";
  }
});

显然,这是非常弱的表单验证—例如,它不会阻止用户验证字段中输入空格或数字的表单—但对于示例目的来说,它是可以的。输出结果如下:
在这里插入图片描述

注意:要获得完整的源代码,请参阅preventdefault-validate .html。

3.6 事件冒泡

事件冒泡(Event bubbling)描述了浏览器如何处理针对嵌套元素的事件。

3.6.1 在父元素上设置监听器

考虑这样一个网页:

<div id="container">
  <button>Click me!</button>
</div>
<pre id="output"></pre>

这里按钮位于另一个元素<div>元素中。我们说这里的<div>元素是它所包含元素的父元素。如果我们向父类添加click事件处理程序,然后单击按钮,会发生什么情况?

const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}

const container = document.querySelector("#container");
container.addEventListener("click", handleClick);

在这里插入图片描述
你会看到,当用户单击按钮时,父类会触发一个click事件:

这是有道理的:按钮位于<div>内部,因此当您单击按钮时,您也隐式地单击了它所在的元素。

3.6.2 冒泡的例子

如果我们向按钮和父控件添加事件侦听器,会发生什么?

<body>
  <div id="container">
    <button>Click me!</button>
  </div>
  <pre id="output"></pre>
</body>

让我们尝试将click事件处理程序添加到按钮、它的父元素(<div>)和包含它们的<body>元素中:

const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}

const container = document.querySelector("#container");
const button = document.querySelector("button");

document.body.addEventListener("click", handleClick);
container.addEventListener("click", handleClick);
button.addEventListener("click", handleClick);

在这里插入图片描述
您将看到,当用户单击按钮时,这三个元素都会触发一个click事件:

You clicked on a BUTTON element
You clicked on a DIV element
You clicked on a BODY element

在这种情况下:

  • 首先触发按钮上的单击
  • 然后是其父元素(<div>元素)的单击
  • 然后是<div>元素的父元素(<body>元素)。

我们将其描述为事件从被点击的最内层元素冒出来( bubbles up)

这种行为可能很有用,但也可能导致意想不到的问题。在接下来的部分中,我们将看到它引起的一个问题,并找到解决方案。

3.6.3 视频播放器示例

在这个例子中,我们的页面包含一个视频,它最初是隐藏的,还有一个标签为“显示视频”的按钮。我们需要以下交互:

  • 当用户点击“显示视频”按钮时,显示包含视频的框,但还没有开始播放视频。
  • 当用户点击视频时,开始播放视频。
  • 当用户点击视频外框中的任何位置时,隐藏该框。

HTML看起来是这样的:

<button>Display video</button>

<div class="hidden">
  <video>
    <source
      src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.webm"
      type="video/webm" />
    <p>
      Your browser doesn't support HTML video. Here is a
      <a href="rabbit320.mp4">link to the video</a> instead.
    </p>
  </video>
</div>

它包括:

  • <button>元素
  • 一个最初具有class="hidden"属性的<div>元素
  • 嵌套在<div>元素中的<video>元素。

我们使用CSS来隐藏带有"hidden"类集的元素。

const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");

btn.addEventListener("click", () => box.classList.remove("hidden"));
video.addEventListener("click", () => video.play());
box.addEventListener("click", () => box.classList.add("hidden"));

您应该看到,当您单击该按钮时,将显示该框及其包含的视频。但是当你点击视频时,视频开始播放,但是盒子又被隐藏了!

视频位于<div>内部——它是<div>的一部分——因此单击视频会同时运行两个事件处理程序,从而导致这种行为。

3.6.4 使用stopPropagation()修复问题

正如我们在上一节中看到的,事件冒泡有时会产生问题,但是有一种方法可以防止它。Event对象上有一个名为stopPropagation()的函数,当在事件处理程序中调用该函数时,可以防止事件冒泡到任何其他元素。

我们可以通过修改JavaScript来解决当前的问题:

const btn = document.querySelector("button");
const box = document.querySelector("div");
const video = document.querySelector("video");

btn.addEventListener("click", () => box.classList.remove("hidden"));

video.addEventListener("click", (event) => {
  event.stopPropagation();
  video.play();
});

box.addEventListener("click", () => box.classList.add("hidden"));

我们在这里所做的只是在<video>元素的’click’事件的处理程序中对事件对象调用stopPropagation()。这将阻止事件冒泡到盒子中。现在试着点击按钮,然后点击视频:

3.6.5 事件捕获

事件传播的另一种形式是事件捕获( event capture。这类似于事件冒泡,但顺序相反:事件不是首先在最内层的目标元素上触发,然后依次在嵌套较少的元素上触发,事件首先在嵌套最少(least nested)的元素上触发,然后依次在嵌套较多的元素上触发,直到到达目标。

默认情况下,事件捕获是禁用的。要启用它,必须在addEventListener()中传递capture 选项。

这个例子就像我们之前看到的冒泡的例子,除了我们使用了capture 选项:

<body>
  <div id="container">
    <button>Click me!</button>
  </div>
  <pre id="output"></pre>
</body>
const output = document.querySelector("#output");
function handleClick(e) {
  output.textContent += `You clicked on a ${e.currentTarget.tagName} element\n`;
}

const container = document.querySelector("#container");
const button = document.querySelector("button");

document.body.addEventListener("click", handleClick, { capture: true });
container.addEventListener("click", handleClick, { capture: true });
button.addEventListener("click", handleClick);

在这里插入图片描述
在这种情况下,消息的顺序是颠倒的:<body>事件处理程序首先触发,然后是<div>事件处理程序,然后是<button>事件处理程序:

为什么要同时捕获和冒泡呢?在糟糕的过去,浏览器的交叉兼容性远不如现在,Netscape只使用事件捕获,Internet Explorer只使用事件冒泡。当W3C决定尝试标准化行为并达成共识时,他们最终采用了包含这两者的系统,这就是现代浏览器实现的。

默认情况下,几乎所有事件处理程序都注册在冒泡阶段,这在大多数情况下更有意义。

3.7 事件委托

在上一节中,我们研究了由事件冒泡引起的问题以及如何修复它。不过,事件冒泡并不只是令人讨厌:它可以非常有用。特别是,它支持事件委托(event delegation。在这个实践中,当我们希望某些代码在用户与大量子元素中的任何一个交互时运行时,我们在它们的父元素上设置事件监听器,并让发生在它们身上的事件冒泡到它们的父元素上,而不必在每个子元素上单独设置事件侦听器。

让我们回到我们的第一个例子,当用户点击一个按钮时,我们设置整个页面的背景颜色。假设,页面被划分为16块区域,当用户点击那个区域时,我们想要设置每个瓷砖的随机颜色。

<div id="container">
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
  <div class="tile"></div>
</div>

我们有一个小小的CSS,用来设置贴图的大小和位置:

.tile {
  height: 100px;
  width: 25%;
  float: left;
}

现在在JavaScript中,我们可以为每个tile添加一个click事件处理程序。但一个更简单、更有效的选择是在父类上设置click事件处理程序,并依靠事件冒泡来确保当用户单击tile时处理程序被执行:

function random(number) {
  return Math.floor(Math.random() * number);
}

function bgChange() {
  const rndCol = `rgb(${random(255)}, ${random(255)}, ${random(255)})`;
  return rndCol;
}

const container = document.querySelector("#container");

container.addEventListener("click", (event) => {
  event.target.style.backgroundColor = bgChange();
});

注意:在本例中,我们使用event.target获取作为事件目标的元素(即最内层元素)。如果我们想要访问处理该事件的元素(在本例中是容器),我们可以使用event.currentTarget

注意:完整的源代码见useful-eventtarget.html;也可以在这里看到它的现场运行。

不仅仅是网页

事件并不是JavaScript独有的——大多数编程语言都有某种事件模型,而模型的工作方式通常与JavaScript的方式不同。事实上,用于网页的JavaScript事件模型不同于用于其他环境的JavaScript事件模型。

例如,Node.js是一个非常流行的JavaScript运行时,它使开发人员能够使用JavaScript构建网络和服务器端应用程序。Node.js事件模型依赖于监听器来监听事件,依赖于发射器来周期性地发出事件——听起来没有什么不同,但代码却大不相同,使用on()等函数来注册事件监听器,使用once()来注册事件监听器,该事件监听器在运行一次后取消注册。HTTP连接事件文档提供了一个很好的例子。

你也可以使用JavaScript构建跨浏览器的插件——使用一种叫做WebExtensions的技术来增强浏览器的功能。事件模型类似于web事件模型,但有一点不同——事件侦听器的属性是以驼峰形式编写的(例如onMessage而不是onmessage),并且需要与addListener函数结合使用。查看runtime.onMessage页面例子。

在学习的这个阶段,你不需要了解其他类似的环境;我们只是想说明事件在不同的编程环境中是不同的。

See also

  • Event reference
  • Event order (关于捕获和冒泡的讨论)——Peter-Paul Koch写的一篇非常详细的文章。
  • 事件访问 (关于事件对象的讨论)——彼得-保罗·科赫的另一篇非常详细的文章
  • domevents.dev 一个非常有用的交互式游乐场应用程序,可以通过探索来学习DOM事件系统的行为。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1065305.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Plotly模拟远古博弈游戏_掷骰子

不乏投资大师、量化基金经理从着迷博弈游戏开始迈出步伐...... 开始学习使用python包Plotly模拟掷骰子。 安装Plotly 终端输入命令&#xff1a;python3 -m pip install --user plotly 创建骰子类 掷骰子 分析结果 绘制直方图 程序都正常运行&#xff0c;直方图也显示无误&…

老胡的周刊(第110期)

老胡的信息周刊[1]&#xff0c;记录这周我看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;内容主题极大程度被我个人喜好主导。这个项目核心目的在于记录让自己有印象的信息做一个留存以及共享。 &#x1f3af; 项目 bitwarden[2] 一个开源&#xff0c;免费&…

代码随想录算法训练营第23期day14|二叉树层序遍历、226.翻转二叉树、101. 对称二叉树

目录 一、二叉树层序遍历 非递归法 递归法 相关题目&#xff08;10题&#xff09; 二、&#xff08;leetcode 226&#xff09;翻转二叉树 递归法 层序遍历 深度优先遍历 1&#xff09;非统一写法——前序遍历 2&#xff09; 统一写法——前序遍历 三、&#xff08;le…

解决spawn-fcgi:child exited with: 127/126/1报错

解决spawn-fcgi:child exited with: 126报错 执行文件的权限不够&#xff0c;如果是使用.sh文件进行执行的&#xff0c;首先对.sh文件进行权限修改 chmod 777 执行文件.sh 之后再对sh文件中所有执行spawn-fcgi的程序授予权限 比如&#xff1a; spawn-fcgi -a 127.0.0.1 -p 789…

【无标题】This project has been opened by another efinity instance

This project has been opened by another efinity instance 说明&#xff1a;&#xff08;1&#xff09;软件自动即出可能有些进程没有关闭 &#xff08;2&#xff09;目录中有中文路径。

对一门不是非常熟悉的语言是怎么面试的

公司是一个基础通讯类的公司&#xff0c;需要的职位是一个高级系统和软件工程师。 职位要求&#xff0c;是一个完全不怎么大众的语言&#xff1a;Elixir。 没听过&#xff0c;这就对了&#xff0c;这是一个函数式的语言&#xff0c;可以认为是 Erlang 的升级版本&#xff0c;…

15073-2014 铸造钛及钛合金 知识梳理

声明 本文是学习GB-T 15073-2014 铸造钛及钛合金.pdf而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准规定了铸造钛及钛合金的牌号、代号和化学成分&#xff0c;以及化学成分分析方法。 本标准适用于机加石墨型、捣实型、金属型和熔模精…

BootstrapBlazor企业级组件库:前端开发的革新之路

作为一名Web开发人员&#xff0c;开发前端我们一般都是使用JavaScript&#xff0c;而Blazor就是微软推出的基于.Net平台交互式客户Web UI 框架&#xff0c;可以使用C#替代JavaScript&#xff0c;减少我们的技术栈、降低学习前端的成本。 而采用Blazor开发&#xff0c;少不了需…

[SWPUCTF 2021 新生赛]sql - 联合注入

这题可以参考文章&#xff1a;[SWPUCTF 2021 新生赛]easy_sql - 联合注入||报错注入||sqlmap 这题相比于参考文章的题目多了waf过滤 首先&#xff0c;仍然是网站标题提示参数是wllm 1、fuzz看哪些关键字被过滤&#xff1a;空格、substr、被过滤 2、?wllm-1/**/union/**/selec…

【Java】CompletableFuture学习记录

目录 介绍创建异步对象计算完成时回调方法handle 方法线程串行化方法两任务组合 - 都要完成两任务组合 - 一个完成多任务组合 介绍 业务场景&#xff1a;查询商品详情页的逻辑比较复杂&#xff0c;有些数据还需要远程调用&#xff0c;必然需要花费更多的时间。 假如商品详情页…

socket网络编程中设置socket选项的ioctlsocket、setsockopt和WSAIoctl函数的使用(附源码)

VC常用功能开发汇总&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&#xff09;https://blog.csdn.net/chenlycly/article/details/124272585C软件异常排查从入门到精通系列教程&#xff08;专栏文章列表&#xff0c;欢迎订阅&#xff0c;持续更新...&a…

AI发展历史

一、AI的发展历史 二、AI发展的第五阶段 &#xff08;一&#xff09;、第一阶段 1.艾伦图灵与模仿游戏 艾伦•图灵&#xff08;Alan Turing&#xff0c;1912~1954&#xff09;是英国数学家、逻辑学家&#xff0c;被称为计算机科学之父&#xff0c;人工智能之父。二战中协助军…

vue重修004【下部】

文章目录 版权声明非父子通信event bus 事件总线实现步骤代码演示 非父子通信-provide&inject语法注意代码演示 v-model原理表单类组件封装& v-model 简化代码.sync修饰符语法代码示例 ref 和 $refs语法代码演示 异步更新 & $nextTick引子$nextTick演示 版权声明 …

javaee ssm框架项目添加分页控件

搭建ssm框架项目 参考上一篇博文 添加分页控件 引入依赖 <?xml version"1.0" encoding"UTF-8"?><project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schema…

关联规则挖掘(下):数据分析 | 数据挖掘 | 十大算法之一

⭐️⭐️⭐️⭐️⭐️欢迎来到我的博客⭐️⭐️⭐️⭐️⭐️ &#x1f434;作者&#xff1a;秋无之地 &#x1f434;简介&#xff1a;CSDN爬虫、后端、大数据领域创作者。目前从事python爬虫、后端和大数据等相关工作&#xff0c;主要擅长领域有&#xff1a;爬虫、后端、大数据…

Kubernetes安装部署 1

本文主要描述kubernetes的安装部署&#xff0c;kubernetes的安装部署主要包括三个关键组件&#xff0c;其中&#xff0c;包括kubeadm、kubelet、kubectl&#xff0c;这三个组件的功能描述如下所示&#xff1a; Kubeadm 用于启动与管理kubernetes集群 Kubelet 运行在所有集群的…

[晕事]今天做了件晕事21;设置代理访问网站的时候需注意的问题

今天在家上班&#xff0c;设置好VPN&#xff0c;通过代理来访问公司内部的一个系统浏览器的反应如下&#xff1a; Hmmm… can’t reach this page ***.com refused to connect. 这个返回的错误&#xff0c;非常的具有迷惑性&#xff0c;提示的意思&#xff1a;拒绝链接&#xf…

Kaggle - LLM Science Exam(二):Open Book QAdebertav3-large详解

文章目录 前言&#xff1a;优秀notebook介绍三、Open Book Q&A3.1 概述3.2 安装依赖&#xff0c;导入数据3.3 数据预处理3.3.1 处理prompt3.3.2 处理wiki数据 3.4 使用faiss搜索获取匹配的Prompt-Sentence Pairs3.5 查看context结果并保存3.6 推理3.6.1 加载测试集3.6.2 定…

模型压缩部署概述

模型压缩部署概述 一&#xff0c;模型在线部署 1.1&#xff0c;深度学习项目开发流程 1.2&#xff0c;模型训练和推理的不同 二&#xff0c;手机端CPU推理框架的优化 三&#xff0c;不同硬件平台量化方式总结 参考资料 一&#xff0c;模型在线部署 深度学习和计算机视觉…

POJ 3264 Balanced Lineup 线段树 / 平方分割

一、题目大意 给出一个长度为 n&#xff08;n<50000) 数组 arr&#xff0c;进行Q次查询&#xff08;Q<200000&#xff09;&#xff0c;每次查询的内容为数组arr在 [L , R] 的切片的极差&#xff08;最大元素 - 最小元素&#xff09; 二、解题思路 1、线段树 区间极差…