单个元素上的多个JS事件处理程序

时间:2013-06-27 19:56:59

标签: javascript jquery dom-events jquery-events

我正在使用现有的网络应用程序,在应用程序中有不同形式的各种提交按钮,一些使用常规的http帖子,一些定义onClick函数,一些使用一个js事件处理程序绑定到按钮关于元素的类。

我想要做的是,通过向按钮添加一个类将另一个事件处理程序绑定到这些按钮,但我想确定的是新事件处理程序是否会被保证执行,或者可能是其中一个表单提交动作发生之前意味着我的新功能没有被击中。

示例场景是我想为这些按钮添加一个类,将它们全部绑定到一个简单的js函数,该函数只是将使用情况记录到某个api。是否存在未调用日志记录功能的风险,因为表单提交已离开页面?

我没有完成大量的js开发,我可以测试100次,只是幸运地解雇它。


下面是我为其中一个示例测试过的一些代码 - 再次,我不是要问如何绑定多个事件,问题是关于我对规范的理解以及是否保证执行所有处理程序。 / p>

$(document).ready(function(){
    $('.testingBtn').click(function() {
        window.location.replace("http://stackoverflow.com");
    });
    $( ".testingBtn" ).click(function(){
        alert('submitting!');
    });
});


<input class="testingBtn" type="submit" id="submitform" value="Complete Signup" />

如上所示,我可以绑定多个事件,在这个例子中,只是指向另一个url,但这可能是form.submit()等。在我的测试中,警报总是首先触发,但我是对竞争条件感到幸运吗?

3 个答案:

答案 0 :(得分:51)

在JS中,

委派是事件模型最强大的功能之一。您可能知道或者可能不知道:在JS中,事件被传递到dom的顶部,从那里传播到应该应用事件的元素。因此,有理由认为,附加到全局对象的事件侦听器会将其处理程序 previous 调用到已附加到元素本身的侦听器。

window.addEventListener('click',function(e)
{
    e = e || window.event;
    var target = e.target || e.srcElement;
    console.log('window noticed you clicked something');
    console.log(target);//<-- this is the element that was clicked
}, false);//<-- we'll get to the false in a minute

重要的是要注意我们实际上可以访问处理程序中的事件对象。在这种情况下,我们保持事件对象不变,因此它将继续向下传播到目标,在它向下的路上,它可能会遇到这样的事情:

document.getElementById('container').addEventListener('click', function(e)
{
    e = e || window.event;
    var target = e.target || e.srcElement;
    if (target.tagName.toLowerCase() !== 'a' || target.className.match(/\bclickable\b/))
    {
        return e;//<return the event, unharmed
    }
    e.returnValue = false;
    if (e.preventDefault)
    {
        e.preventDefault();
    }
}, false);

现在,在窗口级别的侦听器调用其帮助程序之后,将调用此处理程序。这次,如果被点击的元素没有clickable类,或者元素是链接,则事件更改。该事件被取消,但它依旧存在。该事件仍然可以在dom中进一步传播,因此我们可能遇到类似的事情:

document.getElmentById('form3').addEventListener('click',function(e)
{
     e = e || window.event;
     if (e.returnValue === false || e.isDefaultPrevented)
     {//this event has been changed already
         //do stuff, like validation or something, then you could:
         e.cancelBubble = true;
         if (e.stopPropagation)
         {
             e.stopPropagation();
         }
     }
}, false);

在这里,通过调用stopPropagation,该事件将被终止。除非事件已被改变,否则它不能沿着dom进一步传播到其目标。如果没有,事件对象会沿着DOM进一步向下移动,就好像什么都没发生一样。

一旦到达目标节点,事件就会进入第二阶段:泡沫阶段。它不是向下传播到DOM的深处,而是向上攀升到顶层(一直到全局对象,它被派遣到那里......从那里来的所有这些)。

在泡沫阶段,所有相同的规则都适用于传播阶段,只是相反。事件对象将首先遇到最接近目标元素的元素,并且最后会遇到全局对象。

There's a lot of handy, and clear diagrams for this here。我不能把它比任何好的'ol quirksmode更好,所以我建议你阅读他们在那里说的话。

底线:在处理2个事件侦听器时,将它们连接到不同的级别,以便按照您喜欢的方式对它们进行排序。

如果你想保证两者都被调用,只能阻止事件在最后调用的那个处理程序中传播。

当你有两个监听器,附加到同一个事件的相同元素/对象时,我从来没有遇到过第一个连接的监听器的情况,也没有先调用。

就是这样,我上床睡觉,希望我有意义

答案 1 :(得分:9)

jQuery使这很容易。

$(document).on('click', '.someclass', function() {
  doStuff();
});

$(document).on('click', '.someclass', function() {
  doMoreStuff();
});

处理程序然后两者都会点击。 jQuery为你保留了一个汉堡的队列。并处理与您选择的选择器匹配的文档点击,以便无论何时创建按钮都可以触发它们。

答案 2 :(得分:4)

我/我遇到了类似的问题。但是,我不能影响/委托预先存在的“点击”的顺序。事件(由Wicket框架添加)。 但是我仍然需要在之前执行一个新的自定义事件任何一次点击&#39;或者改变&#39;框架处理的事件。

幸运的是,有几个事件实际按顺序执行。 &#39; mousedown&#39;而且“老鼠&#39;碰巧发生在“点击”之前。
http://en.wikipedia.org/wiki/DOM_events

$(document).on('mousedown', function (event) {
  event = event || window.event
  var target = event.target || event.srcElement;
  console.log(target + ' before default event'); // Hold mouse button down to see this message in console before any action is executed
});

OR

$(document).on('mouseup', function (event) {
  event = event || window.event
  var target = event.target || event.srcElement;
  alert(target + ' before default event'); // You may not notice this event fires when the page changes unless this is an alert
});

这将允许在执行实际事件之前完成日志记录(例如,通过ajax)。通过(ajax)链接更改页面。

当然,您可能需要使用更复杂的方法来检测应该执行的其他事件处理,但您可以使用例如&#39; target&#39;这方面的信息。 =&GT;这个脚本监视页面上的所有内容,因为这就是我需要完成的工作。