当前位置: 首页 > news >正文

js 事件参考

事件参考

事件介绍

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

每个事件都由一个基于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 elementthis.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><sourcesrc="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事件系统的行为。

相关文章:

js 事件参考

事件参考 事件介绍 触发事件是为了通知代码可能影响代码执行的“有趣变化”。这些可能来自用户交互&#xff0c;例如使用鼠标或调整窗口大小&#xff0c;底层环境状态的变化(例如&#xff0c;低电量或来自操作系统的媒体事件)以及其他原因。 每个事件都由一个基于Event接口的…...

卷积网络的发展历史-LeNet

简介 LeNet是CNN结构的开山鼻祖&#xff0c;第一次定义了卷积神经网络的结构。 LeNet模型包含了多个卷积层和池化层&#xff0c;以及最后的全连接层用于分类。其中&#xff0c;每个卷积层都包含了一个卷积操作和一个非线性激活函数&#xff0c;用于提取输入图像的特征。池化层…...

(2023,GPT-4V,LLM,LMM,功能和应用)大型多模态模型的黎明:GPT-4V(ision) 的初步探索

The Dawn of LMMs: Preliminary Explorations with GPT-4V(ision) 公众号&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 1.1 动机和概述 1.2 我们探索 GPT-4V 的方法 1.3…...

【C++设计模式之装饰模式:结构型】分析及示例

装饰模式&#xff08;Decorator Pattern&#xff09;是一种结构型设计模式&#xff0c;它允许在运行时动态地给一个对象添加额外的行为。 描述 装饰模式通过创建一个包装器&#xff08;Wrapper&#xff09;来包裹原始对象&#xff0c;并在原始对象的行为前后添加额外的功能。…...

绘制散点图、曲线图、折线图和环形图失败, 设置迭代次数和进度无法保存图片

错误❌ 分别input设置&#xff08;我想知道微积分的力量&#xff09; 设1个人&#xff0c;他有每天3种方案&#xff0c;每天进步千分之一&#xff0c;千分之一&#xff0c;十万分之一等到他们迭代 200,500,1000,2000,3000,5000,9000次 他们在图片什么位置画曲线图&#xff0…...

micro-ROS中对消息的内存管理

文章目录 1.背景2.答案2.1.基本类型及其数组&#xff0c;不需要2.1.序列类型&#xff08;复合类型、复合序列类型&#xff09;&#xff0c;需要 3.内存申请方法3.1.手动申请&#xff08;Manual allocation&#xff09;3.1.工具辅助&#xff08;micro-ROS utilities&#xff09;…...

Springboot中使用拦截器、过滤器、监听器

一、Servlet、Filter&#xff08;过滤器&#xff09;、 Listener&#xff08;监听器&#xff09;、Interceptor&#xff08;拦截器&#xff09; Javaweb三大组件&#xff1a;servlet、Filter&#xff08;过滤器&#xff09;、 Listener&#xff08;监听器&#xff09; Spring…...

代码随想录二刷day45

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣70. 爬楼梯二、力扣322. 零钱兑换三、力扣279. 完全平方数 前言 一、力扣70. 爬楼梯 class Solution {public int climbStairs(int n) {int[] dp new…...

泊车功能专题介绍 ———— AVP系统基础数据交互内容

文章目录 系统架构系统功能描述云端子系统车辆子系统场端子系统用户APP 工作流程基础数据交互内容AVP 系统基础数据交互服务车/用户 - 云基础数据交互内容车位查询工作流程技术要求数据交互要求 车位预约工作流程技术要求数据交互要求 取消预约工作流程技术要求数据交互要求 泊…...

蓝桥杯每日一题2023.10.6

题目描述 门牌制作 - 蓝桥云课 (lanqiao.cn) 题目分析 #include<bits/stdc.h> using namespace std; int ans; int main() {for(int i 1; i < 2020; i ){int x i;while(x){int a x % 10;if(a 2)ans ;x / 10;}}cout << ans;return 0; } 题目描述 既约分数…...

7、【Qlib】【主要组件】Data Layer:数据框架与使用

7、【主要组件】Data Layer&#xff1a;数据框架与使用 简介数据准备Qlib 格式数据Qlib 格式数据集自动更新日频率数据将 CSV 格式转换为 Qlib 格式股票池&#xff08;市场&#xff09;多股票模式 数据API数据检索特征过滤器 数据加载器QlibDataLoaderStaticDataLoaderInterfac…...

Kubernetes安装部署 1

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

在VS Code中优雅地编辑csv文件

文章目录 Rainbow csv转表格CSV to Tablecsv2tableCSV to Markdown Table Edit csv 下面这些插件对csv/tsv/psv都有着不错的支持&#xff0c;这几种格式的主要区别是分隔符不同。 功能入口/使用方法Rainbow csv按列赋色右键菜单CSV to Table转为ASCII表格指令CSV to Markdown …...

LCR 128.库存管理 I

​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;LCR 128. 库存管理 I - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 数组可以分割成两段的升序连续子数组&#xff0c;找到两个子数组的开始元素并返回较小者即可。 解题代码&#xff1a; …...

eigen::Affine3d 转换

平移eigen::vector3d和四元数Eigen::Quaterniond 转 eigen::Affine3d Eigen::Vector3d t Eigen::Vector3d::Zero(); Eigen::Quaterniond q Eigen::Quaterniond ::Identity();Eigen::Affine3d affine3d t * q.toRotationMatrix(); Eigen::Matrix4d 转 eigen::Affine3d Eige…...

【Python从入门到进阶】38、selenium关于Chrome handless的基本使用

接上篇《37、selenium关于phantomjs的基本使用》 上一篇我们介绍了有关phantomjs的相关知识&#xff0c;但由于selenium已经放弃PhantomJS&#xff0c;本篇我们来学习Chrome的无头版浏览器Chrome Handless的使用。 一、Chrome Headless简介 Chrome Headless是一个无界面的浏览…...

给Python项目创建一个虚拟环境(enev)

给Python项目创建一个虚拟环境&#xff08;enev&#xff09; 为您的Python项目创建一个虚拟环境是一种良好的实践&#xff0c;可以隔离项目的依赖项&#xff0c;以确保它们不会干扰全局Python环境或其他项目。您可以使用venv模块来创建虚拟环境。以下是在Linux上创建虚拟环境的…...

【RK3588】YOLO V5在瑞芯微板子上部署问题记录汇总

YOLO V5训练模型部署到瑞芯微的板子上面&#xff0c;官方是有给出案例和转过详情的。并且也提供了Python版本的推理代码&#xff0c;以及C语言的代码。 但是&#xff0c;对于转换过程中的细节&#xff0c;哪些需要改&#xff1f;怎么改&#xff1f;如何改&#xff0c;和为什么…...

别人做的百度百科词条信息不全,如何更正自己的百度百科词条

很多人自己的百度百科词条是别人上传上去的&#xff0c;自己压根不知道&#xff0c;而且里面的信息内容要么不全&#xff0c;要么是有错漏的&#xff0c;但自己想要更正自己的百度百科词条又不知道如何更正&#xff0c;下面洛希爱做百科网和大家介绍一些百科经验知识。 首先百…...

[论文精读]U-Net: Convolutional Networks for BiomedicalImage Segmentation

论文原文&#xff1a;U-Net: Convolutional Networks for Biomedical Image Segmentation (arxiv.org) 英文是纯手打的&#xff01;论文原文的summarizing and paraphrasing。可能会出现难以避免的拼写错误和语法错误&#xff0c;若有发现欢迎评论指正&#xff01;文章偏向于笔…...

生成xcframework

打包 XCFramework 的方法 XCFramework 是苹果推出的一种多平台二进制分发格式&#xff0c;可以包含多个架构和平台的代码。打包 XCFramework 通常用于分发库或框架。 使用 Xcode 命令行工具打包 通过 xcodebuild 命令可以打包 XCFramework。确保项目已经配置好需要支持的平台…...

手游刚开服就被攻击怎么办?如何防御DDoS?

开服初期是手游最脆弱的阶段&#xff0c;极易成为DDoS攻击的目标。一旦遭遇攻击&#xff0c;可能导致服务器瘫痪、玩家流失&#xff0c;甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案&#xff0c;帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

微信小程序 - 手机震动

一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注&#xff1a;文档 https://developers.weixin.qq…...

《通信之道——从微积分到 5G》读书总结

第1章 绪 论 1.1 这是一本什么样的书 通信技术&#xff0c;说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号&#xff08;调制&#xff09; 把信息从信号中抽取出来&am…...

前端开发面试题总结-JavaScript篇(一)

文章目录 JavaScript高频问答一、作用域与闭包1.什么是闭包&#xff08;Closure&#xff09;&#xff1f;闭包有什么应用场景和潜在问题&#xff1f;2.解释 JavaScript 的作用域链&#xff08;Scope Chain&#xff09; 二、原型与继承3.原型链是什么&#xff1f;如何实现继承&a…...

Spring数据访问模块设计

前面我们已经完成了IoC和web模块的设计&#xff0c;聪明的码友立马就知道了&#xff0c;该到数据访问模块了&#xff0c;要不就这俩玩个6啊&#xff0c;查库势在必行&#xff0c;至此&#xff0c;它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据&#xff08;数据库、No…...

Linux --进程控制

本文从以下五个方面来初步认识进程控制&#xff1a; 目录 进程创建 进程终止 进程等待 进程替换 模拟实现一个微型shell 进程创建 在Linux系统中我们可以在一个进程使用系统调用fork()来创建子进程&#xff0c;创建出来的进程就是子进程&#xff0c;原来的进程为父进程。…...

Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信

文章目录 Linux C语言网络编程详细入门教程&#xff1a;如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket&#xff08;服务端和客户端都要&#xff09;2. 绑定本地地址和端口&#x…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...