多个addEventListener如何在JavaScript中工作?

时间:2013-04-29 07:48:25

标签: javascript javascript-events addeventlistener

文档中有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;
};

为确保我的点击事件不被其他脚本覆盖,我切换到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);

现在我又得到了一个问题。由于第二个代码中的return false是在alert之后定义的,为什么它不会阻止警报被调用?

如果我希望我的脚本能够完全控制click事件(比如忽略其他脚本中定义的事件,则一直返回false)会怎样?

1 个答案:

答案 0 :(得分:46)

  

如果我希望我的脚本能够完全控制click事件(比如忽略其他脚本中定义的事件,则一直返回false)会怎样?

如果你可以先注册你的处理程序,那么你可以这样做,只要你正在使用的浏览器正确地实现了DOM3事件(除非它是IE8或更早版本,它可能会这样做。)

这里涉及(至少)四件事:

  1. 防止默认。

  2. 停止传播到祖先元素。

  3. 停止调用相同元素上的其他处理程序。

  4. 调用处理程序的顺序。

  5. 按顺序:

    1。防止默认

    这是来自DOM0处理程序的return false。 (详情:The Story on Return False。)DOM2和DOM3中的等价物是preventDefault

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

    防止默认值可能与您正在做的事情无关,但由于您在DOM0处理程序中使用return false,并且这会阻止默认值,因此我将其包含在此处以保证完整性。< / p>

    2。停止传播到祖先元素

    DOM0处理程序无法执行此操作。 DOM2可以通过stopPropagation

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

    但是stopPropagation并没有阻止同一个元素被调用的其他处理程序。来自the spec

      

    使用stopPropagation方法防止在事件流期间进一步传播事件。如果任何EventListener调用此方法,则事件将停止在树中传播。 事件将在事件流程停止之前完成对当前EventTarget的所有侦听器的调度。

    (我的重点。)

    3。阻止相同元素上的其他处理程序被调用

    当然,DOM0没有出现这种情况,因为在同一个元素上,同样的事件不能 其他处理程序。 : - )

    据我所知,在DOM2中无法做到这一点,但DOM3为我们提供了stopImmediatePropagation

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

    有些库提供此功能(即使在IE8等非DOM3系统上),也可以通过库连接处理程序,如下所示。

    4。调用处理程序的顺序

    同样,不是与DOM0相关的东西,因为没有其他处理程序。

    在DOM2中,规范显式表示不保证调用附加到元素的处理程序的顺序;但是DOM3改变了这一点,说处理程序是按照它们注册的顺序调用的。

    首先,来自DOM2 Section 1.2.1

      

    虽然EventListeners上的所有EventTarget都可以保证由EventTarget收到的任何事件触发,但是没有规定它们将接收的顺序有关EventListeners上其他EventTarget的事件。

    但这已被DOM3 Section 3.1取代:

      

    接下来,实现必须确定当前目标的候选事件侦听器。这必须是已按照注册顺序>在当前目标上注册的所有事件侦听器的列表。

    (我的重点。)

    如果您将事件与库挂钩,某些库可以保证订单。

    值得注意的是,在Microsoft的DOM2的前身(例如,attachEvent)中,它与DOM3的顺序相反:处理程序以 reverse 注册顺序调用。


    所以将#3和#4放在一起,如果你可以先注册你的处理程序,它将首先被调用,你可以使用stopImmediatePropagation来阻止其他处理程序被调用。如果浏览器正确实现DOM3。


    所有这一切(包括IE8及其早期甚至不实现DOM2事件,更不用说DOM3)的事实是人们使用像jQuery这样的库的一个原因,其中一些确实保证了订单(只要一切都在挂钩)他们的处理程序通过相关的库)并提供方法来阻止其他处理程序在相同的元素被调用。 (例如,使用jQuery,顺序是它们被附加的顺序,你可以使用stopImmediatePropagation来停止对其他处理程序的调用。但我不是想在这里销售jQuery,只是解释一些库提供比基本DOM内容更多的功能。)