简体   繁体   English

多个 addEventListener 在 JavaScript 中如何工作?

[英]How do multiple addEventListener work in JavaScript?

There are 2 scripts in a document一个文档中有 2 个脚本

// my_script.js goes first
document.onclick = function() {
    alert("document clicked");
};

// other_script.js comes after
// this overrides the onclick of my script,
// and alert will NOT be fired
document.onclick = function() {
    return false;
};

To make sure my click event does not get overridden by other script, I switched to addEventListener .为了确保我的点击事件不会被其他脚本覆盖,我切换到addEventListener

// my_script.js goes first
document.addEventListener("click", function() {
    alert("document clicked");
}, false);

// other_script.js comes after
document.addEventListener("click", function() {
    return false;
}, false);

Now I got another question.现在我有另一个问题。 Since return false in the second code is defined after alert , how come it does not prevent alert from being called?由于第二个代码中的return false是在alert之后定义的,为什么它不阻止 alert 被调用?

What if I want my script to get total control of click event (like return false all the time disregarding events defined in other scripts)?如果我希望我的脚本完全控制点击事件(例如始终返回 false,而忽略其他脚本中定义的事件),该怎么办?

What if I want my script to get total control of click event (like return false all the time disregarding events defined in other scripts)?如果我希望我的脚本完全控制点击事件(例如始终返回 false,而忽略其他脚本中定义的事件),该怎么办?

If you can register your handler first, before they do, you can do that, provided the browser you're using correctly implements DOM3 events (which it probably does unless it's IE8 or earlier).如果您可以先注册您的处理程序,那么您就可以这样做,前提是您使用的浏览器正确实现了 DOM3 事件(除非是 IE8 或更早版本,否则它可能会这样做)。

There are (at least) four things involved here:这里涉及(至少)四件事:

  1. Preventing the default.防止默认。

  2. Stopping propagation to ancestor elements.停止传播到祖先元素。

  3. Stopping other handlers on the same element from being called.停止调用同一元素上的其他处理程序。

  4. The order in which handlers are called.调用处理程序的顺序。

In order:为了:

1. Preventing the default 1. 防止默认

This is what return false from a DOM0 handler does.这就是 DOM0 处理程序的return false所做的。 (Details: The Story on Return False .) The equivalent in DOM2 and DOM3 is preventDefault : (详细信息: 返回 False 的故事。)DOM2 和 DOM3 中的等价物是preventDefault

document.addEventListener("click", function(e) {
    e.preventDefault();
}, false);

Preventing the default may not be all that relevant to what you're doing, but since you were using return false in your DOM0 handler, and that prevents the default, I'm including it here for completeness.防止默认值可能与您正在做的事情无关,但由于您在 DOM0 处理程序中使用了return false ,这会阻止默认值,为了完整起见,我将其包含在此处。

2. Stopping propagation to ancestor elements 2.停止传播到祖先元素

DOM0 handlers have no way to do this. DOM0 处理程序无法做到这一点。 DOM2 ones do, via stopPropagation : DOM2 的,通过stopPropagation

document.addEventListener("click", function(e) {
    e.stopPropagation();
}, false);

But stopPropagation doesn't stop other handlers on that same element getting called.但是stopPropagation不会停止调用同一元素上的其他处理程序。 From the spec :规范

The stopPropagation method is used prevent further propagation of an event during event flow. stopPropagation方法用于防止事件流期间事件的进一步传播。 If this method is called by any EventListener the event will cease propagating through the tree.如果此方法被任何EventListener调用,则事件将停止在树中传播。 The event will complete dispatch to all listeners on the current EventTarget before event flow stops.该事件将在事件流停止之前完成对当前EventTarget上的所有侦听器的调度。

(My emphasis.) (我的重点。)

3. Stopping other handlers on the same element from being called 3. 停止调用同一元素上的其他处理程序

Naturally, this didn't come up for DOM0, because there couldn't be other handlers for the same event on the same element.自然,这不会出现在 DOM0 上,因为在同一元素上不可能其他处理程序来处理同一事件。 :-) :-)

As far as I'm aware, there's no way to do this in DOM2, but DOM3 gives us stopImmediatePropagation :据我所知,在 DOM2 中没有办法做到这一点,但 DOM3 给了我们stopImmediatePropagation

document.addEventListener("click", function(e) {
    e.stopImmediatePropagation();
}, false);

Some libraries offer this feature (even on non-DOM3 systems like IE8) for handlers hooked up via the library, see below.一些库为通过库连接的处理程序提供此功能(即使在非 DOM3 系统上,如 IE8),请参见下文。

4. The order in which handlers are called 4. 处理程序的调用顺序

Again, not something that related to DOM0, because there couldn't be other handlers.同样,与 DOM0 无关,因为不可能有其他处理程序。

In DOM2, the specification explicitly says that the order in which the handlers attached to an element are called is not guaranteed;在 DOM2 中,规范明确表示不保证调用附加到元素的处理程序的顺序; but DOM3 changes that, saying that handlers are called in the order in which they're registered.但是 DOM3 改变了这一点,说处理程序按照它们注册的顺序被调用。

First, from DOM2 Section 1.2.1 :首先,来自 DOM2 Section 1.2.1

Although all EventListeners on the EventTarget are guaranteed to be triggered by any event which is received by that EventTarget , no specification is made as to the order in which they will receive the event with regards to the other EventListeners on the EventTarget .尽管EventTarget上的所有EventListeners都保证由该EventTarget接收的任何事件触发,但没有指定它们将接收事件的顺序与EventTarget上的其他EventListeners

But this is superceded by DOM3 Section 3.1 :但这被 DOM3第 3.1 节取代:

Next, the implementation must determine the current target's candidate event listeners.接下来,实现必须确定当前目标的候选事件侦听器。 This must be the list of all event listeners that have been registered on the current target in their order of registration .这必须是按注册顺序在当前目标上注册的所有事件侦听器的列表。

(My emphasis.) (我的重点。)

Some libraries guarantee the order, provided you hook up the events with the library.一些库可以保证顺序,前提是您将事件与库连接起来。

It's also worth noting that in Microsoft's predecessor to DOM2 (eg, attachEvent ), it was the opposite of DOM3's order: The handlers were called in reverse order of registration.还值得注意的是,在 Microsoft DOM2 的前身(例如, attachEvent )中,它与 DOM3 的顺序相反:以注册的相反顺序调用处理程序。


So taking #3 and #4 together, if you can register your handler first, it will get called first, and you can use stopImmediatePropagation to prevent other handlers getting called.因此,将 #3 和 #4 放在一起,如果您可以先注册您的处理程序,它将首先被调用,您可以使用stopImmediatePropagation来防止其他处理程序被调用。 Provided the browser implements DOM3 correctly.前提是浏览器正确实现了 DOM3。


All of this (including the fact that IE8 and earlier don't even implement DOM2 events, much less DOM3) is one reason people use libraries like jQuery, some of which do guarantee the order (as long as everything is hooking up their handlers via the library in question) and offer ways to stop even other handlers on the same element getting called.所有这些(包括 IE8 及更早版本甚至不实现 DOM2 事件,更不用说 DOM3)是人们使用像 jQuery 这样的库的原因之一,其中一些库确实保证了顺序(只要一切都通过有问题的库)并提供方法来停止调用同一元素上的其他处理程序。 (With jQuery, for instance, the order is the order in which they were attached, and you can use stopImmediatePropagation to stop calls to other handlers. But I'm not trying to sell jQuery here, just explaining that some libs offer more functionality than the basic DOM stuff.) (例如,对于 jQuery,顺序是它们被附加的顺序,您可以使用stopImmediatePropagation来停止对其他处理程序的调用。但我并不想在这里推销 jQuery,只是解释一些库提供的功能比基本的 DOM 东西。)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM