内联onclick与addeventlistener的顺序是什么,为什么? [英] What is the order of inline onclick vs addeventlistener and why?

查看:97
本文介绍了内联onclick与addeventlistener的顺序是什么,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑此按钮:

 < button id ="the_button" onclick ="RunOnClick();"> Click</button> 

此按钮具有一个内联的 onclick 事件处理程序. RunOnClick 函数的内容与这个问题无关.

如果我还附加另一个click事件监听器,如下所示:

  var btn = document.getElementById('the_button');btn.addEventListener("click",function(){//做一点事}); 

addEventListener 注册的处理程序似乎总是在内联 onclick =" 之后运行.

我是否可以始终依靠单个内联 onclick 处理程序首先触发,而 addEventListener 处理程序稍后触发?

这是fl幸吗?还是实际上是按照ECMAScript规范之一的一部分进行设计的?

这听起来像是基本问题的问题,但我不知道答案.

解决方案

答案是,是的,这实际上涵盖在规范中,但本身并未涵盖ECMAScript规范,ECMAScript规范仅严格处理与实现无关的ECMAScript.>

首先,DOM事件的顺序.我向您介绍这个相关的SO问题.

JavaScript中的事件处理程序是否按顺序调用?

如前所述,以前未指定,但截至 DOM级别3规范确实声明应按照注册顺序执行它们.

但是像您的示例中定义的内联事件处理程序呢?

为此,我们可以转到 onclick 属性)的操作会将事件侦听器添加到DOM规范前面提到的列表中.

  • 幕后实际上发生的是,此事件侦听器严格来说不是您在 onclick 属性中指定的代码,而是内部事件处理程序处理算法,用于评估该属性并执行适当的回调.
  • 重要的是,当属性更改或设置为null时,事件侦听器及其在列表中的位置不会更改.仅更改事件处理程序处理算法的结果(因为您已经更改了输入).
  • 这可能有点令人困惑.自己阅读和摘要说明可能会有所帮助,但我还将尝试介绍以下关键含义.

    首先,是的,您看到的行为已由规范有效地定义为规范告诉我们的逻辑结果.当文档被解析并遇到内联事件处理程序属性时,此内部算法将立即添加到事件侦听器列表中.根据规范,这意味着第一个事件侦听器将是与您的事件处理程序属性相对应的侦听器.由于必须在对 addEventListener 的任何调用之前设置此设置,因为不可能在当时不存在的元素上调用 addEventListener .在这种情况下,它将始终优先执行.

    当我们在初始解析后开始使用inline属性时,会发生有趣的事情.这是HTML5规范本身的示例,出现在我上面引用的代码之后:

    示例8

    此示例演示了事件侦听器的调用顺序.如果用户单击此示例中的按钮,该页面将显示四个警报,分别为文本一个",两个",三个"和四个".

     < button id ='test'>开始演示</button>< script>var button = document.getElementById('test');button.addEventListener('click',function(){alert('ONE')},false);button.setAttribute('onclick',"alert('NOT CALLED')");//事件处理程序侦听器已在此处注册button.addEventListener('click',function(){alert('THREE')},false);button.onclick = function(){alert('TWO');};button.addEventListener('click',function(){alert('FOUR')},false);</script> 

    我们可以看到,onclick属性的初始值被覆盖,但是新的onclick处理程序仍然在使用 addEventListener 设置的第一个和第二个侦听器之间执行.这样做的原因是,内联事件处理程序将始终始终在首次将其添加到元素时的同一时间出现在侦听器列表中.从技术上讲,这是因为从技术上讲,如前所述,实际的事件侦听器不是我们在属性内容中指定的回调,而是将属性内容作为输入的内部算法.

    我已经创建了 JSFiddle 来测试这种情况,并且我可以确认这是行为我在Firefox和Chrome中都能看到.


    实际上,总结一下:

    1. 在第一次加载时在文档源中遇到的事件处理程序属性将始终优先执行,因为它们之前可能没有添加事件侦听器.
    2. 对于稍后添加了 setAttribute 的事件处理程序属性,则它们将遵循分别添加到 addEventListener 的早期和以后调用的顺序.
    3. 无论如何更改或取消设置事件处理程序属性的值,都不会更改其在事件侦听器列表中的位置.

    希望能把事情弄清楚!

    Consider this button:

    <button id="the_button" onclick="RunOnClick();">Click</button>
    

    This button has an inline onclick event handler. The contents of the RunOnClick function don't matter for this question.

    If I ALSO attach another click event listener like so:

    var btn = document.getElementById('the_button');
    
    btn.addEventListener("click", function(){
        // Do Something
    });
    

    The handler registered with addEventListener always seems to run after the inline onclick="" one.

    Can I always rely on the single inline onclick handler to fire first and the addEventListener handler to fire later?

    Is this a fluke? Or is it actually designed that way and part of one of the ECMAScript specifications?

    This feels like a back to the basics quality of question, but I don't know the answer.

    解决方案

    The answer is, yes, this is actually covered in the specification but not the ECMAScript spec per se, which only strictly deals with ECMAScript independent of implementation.

    Firstly, the ordering of DOM events. I refer you to this relevent SO question.

    Are event handlers in JavaScript called in order?

    As this states, previously it was unspecifed but as of the DOM level 3 spec it does specifically state they should be executed in the order that they are registered.

    But what about inline event handlers defined like in your example?

    For this we can turn to the HTML 5 spec which says:

    An event handler content attribute is a content attribute for a specific event handler. The name of the content attribute is the same as the name of the event handler.

    [...]

    When an event handler H of an element or object T implementing the EventTarget interface is first set to a non-null value, the user agent must append an event listener to the list of event listeners associated with T with type set to the event handler event type corresponding to H and callback set to the event handler processing algorithm defined below.

    Unpacking this and the subsequent notes a bit the key things to take away here are:

    • The act of adding an 'event handler content attribute' (e.g. your onclick attribute) will cause an event listener to be added to the list referred to earlier in the DOM spec.
    • What is actually happening behind the scenes is that this event listener is not strictly the code you specified in the onclick attribute but an internal event handler processing algorithm for evaluating the attribute and executing the appropriate callback.
    • Importantly when the attribute changes or is set to null then the event listener, and it's position in the list, is not changed. Only the outcome of the event handler processing algorithm is changed (because you have changed the input).

    This might be a bit confusing. It might help to read and digest the notes on the spec yourself, but I will also try to cover the key implications below.

    Firstly, yes, the behaviour you see is effectively defined by the spec as a logical result of what the spec tells us. When a document is being parsed and encounters an inline event handler attribute then this internal algorithm is added to the list of event listeners immediately. According to the spec then this will mean that the first event listener will be the one corresponding to your event handler attribute. Since this has to have been set before any calls to addEventListener since it wouldn't be possible to call addEventListener on a element that didn't exist then. In these circumstances it will always execute first.

    The interesting stuff happens when we start messing with the inline attribute after the initial parsing. Here's an example from the HTML5 spec itself that appears right after the bit I quoted above:

    EXAMPLE 8

    This example demonstrates the order in which event listeners are invoked. If the button in this example is clicked by the user, the page will show four alerts, with the text "ONE", "TWO", "THREE", and "FOUR" respectively.

     <button id='test'>Start Demo</button>
        <script>
        var button = document.getElementById('test');
        button.addEventListener('click', function () { alert('ONE') }, false);
        button.setAttribute('onclick', "alert('NOT CALLED')"); // event handler listener is registered here
        button.addEventListener('click', function () { alert('THREE') }, false);
        button.onclick = function () { alert('TWO'); };
        button.addEventListener('click', function () { alert('FOUR') }, false);
        </script>
    

    As we can see then the initial value of the onclick attribute is overriden, but the new onclick handler still executes between the first and the second listener set with addEventListener. The reason for this is that the inline event handler will effectively always be in the list of listeners at the same point it was when it was first added to the element. This is because technically, as stated earlier, the actual event listener is not the callback we have specified in the attribute content, but an internal algorithm that takes the attribute contents as it's input.

    I have created a JSFiddle to test this is the case and I can confirm this is the behaviour I see in both Firefox and Chrome.


    So to summarise, in practical terms:

    1. Event handler attributes, encountered in a documents source when first loading, will always execute first since they could not have had an event listener added before.
    2. For event handler attributes added later with e.g setAttribute, then they will respect the order in which they were added respective to earlier and later calls to addEventListener.
    3. However changing or unsetting the value of an event handler attribute will not change it's position in the list of event listeners.

    Hope that clears things up!

    这篇关于内联onclick与addeventlistener的顺序是什么,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆