单个元素上的多个js事件处理程序 [英] multiple js event handlers on single element

查看:158
本文介绍了单个元素上的多个js事件处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用现有的网络应用程序,在应用程序中有各种不同形式的提交按钮,有些使用常规的http post,有些定义了onClick函数,还有一些使用类的元素。



我想要做的是通过向按钮添加一个类来绑定另一个事件处理程序,但是我想确定的是会保证新的事件处理程序被执行,或者可能会发生表单提交操作之一发生之前​​它意味着我的新功能没有被打。



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



我没有完成js开发的负载,我






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



<$ ()函数(){
window.location.replace( );
$(.testingBtn).click(function(){
alert('submitting!');
});
});


< input class =testingBtntype =submitid =submitformvalue =Complete Signup/>

如上所示,我可以绑定多个事件,并且在此示例中,仅指向另一个url ,但这可能是一个 form.submit()等等。在我的测试中,警报总是首先被解雇,但我是否在比赛条件中幸运?

解决方案

在JS中,您并不真正拥有控制事件处理程序调用顺序的控制权,谨慎的委派和良好的听众,这是可能的。

委托是事件模型最强大的功能之一。正如你可能会或可能不知道的那样:在JS中,事件被传递到dom的顶部,从它传播到应用事件的元素。因此,有理由认为,附加到全局对象的事件监听器会在它之前调用它的处理程序到已经附加到该元素本身的监听器。

  window.addEventListener('click',function(e)
{
e = e || window.event;
var target = e.target || e.srcElement;
console.log('窗口注意到你点击了某物');
console.log(target); //< - 这是被点击的元素
},false); //< - 我们会在一分钟内得到false

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



< pre $ 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; //<返回事件,不受伤害
}
e.returnValue = false;
if(e.preventDefault)
{
e.preventDefault();
}
},false);

现在,这个处理程序将在窗口级侦听器调用它的助手之后被调用。这次,如果clicked元素没有可点击的类,或者元素是链接,那么事件会被更改。这个事件被取消了,但它仍然存在。该事件仍然可以自由传播,因此我们可能会遇到如下情况:

  document.getElmentById('form3' ).addEventListener('click',function(e)
{
e = e || window.event;
if(e.returnValue === false || e.isDefaultPrevented)
{//这个事件已经被改变
//做些东西,比如验证或者其他东西,那么你可以:
e.cancelBubble = true;
if(e.stopPropagation)
{
e.stopPropagation();
}
}
},false);

这里,通过调用 stopPropagation 被杀害。除非事件已经发生变化,否则它不能向下传播到目标。如果没有,事件对象会进一步向下移动到DOM,就好像什么也没有发生。



一旦到达目标节点,事件就进入第二阶段:泡泡阶段。它不是向下传播到DOM深处,而是爬回到顶层(一路到达全局对象,在那里被调度......从它发生的地方和所有那些地方)。



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



这里有很多方便,清晰的图表。我不能说比任何好的'ol quirksmode都好,所以我建议你阅读他们在那里说的话。



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



如果要保证两者都被调用,只需停止事件传播



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

就这样,我睡觉了,希望我有意义


I am working with an existing web app, in the app there are a variety of submit buttons on different forms, some using regular http post, some defining an onClick function, and some binding a js event handler to the button using a class on the element.

What I want to do, is bind another event handler to these buttons by just adding a class to the buttons, but what I want to determine is will the new event handler be guaranteed to be executed, or could one of the form submit actions happen before it does meaning my new function isn't hit.

The example scenario is I want to add a class to these buttons that bimds them all to a common js function that simply logs usage to some api. Is there a risk that the logging function isn't called because the form submit has navigated away from the page?

I've not done loads of js development, and I could test this 100 times over and just get lucky with it firing.


Below is some code I have tested with for one of the examples - again, I'm not asking how to bind multiple events, the question is to about my understanding of the spec and whether execution of all handlers is guaranteed.

$(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" />

As seen above, I can bind the multiple events, and in this example, just directed to another url, but this could be a form.submit() etc. In my testing the alert has always fired first, but am I just getting lucky with the race conditions?

解决方案

In JS, you don't really have control over what order the event handlers are called, but with careful delegation and well-placed listeners, it is possible.

Delegation is one of the most powerful features of the event model. As you may or may not know: in JS, an event is handed to the top of the dom, from where it propagates down to the element onto which the event should be applied. It stands to reason, therefore, that an event listener attached to the global object will call its handler prior to a listener that has been attached to the element itself.

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

It's important to note we actually have access to the event object in the handlers. In this case, we left the event object untouched, so it'll just continue to propagate down to the target, on its way down, it might meet with something like this:

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);

Now, this handler will be called after the listener at the window level calls its helper. This time, the event is changed if the clicked element didn't have the clickable class, or the element is a link. The event is canceled, but it lives on, still. The event is still free to propagate further down the dom, so we might encounter something like:

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);

Here, by calling stopPropagation, the event is killed off. It can't propagate further down the dom to its target unless the event was already altered. If not, the event object travels further down the DOM, as if nothing happened.

Once it reaches its target node, the event enters its second phase: the bubble phase. Instead of propagating down into the deeps of the DOM, it climbs back up, to the top level (all the way to the global object, where it was dispatched... from whence it came and all that).

In the bubble phase, all the same rules apply as in the propagation phase, only the other way around. The event object will encounter the elements that are closest to the target element first, and the global object last.

There's a lot of handy, and clear diagrams for this here. I can't put it any better than good 'ol quirksmode, so I suggest you read what they have to say there.

Bottom line: when dealing with 2 event listeners, attach them both on a different level to sort-of queue them the way you like.

If you want to guarantee both are called, only stop the event from propagating in that handler that will be called last.

When you've got two listeners, attached to the same element/object for the same event, I've never come across a situation where the listener that was attached first, wasn't also called first.

That's it, I'm off to bed, hoping I made sense

这篇关于单个元素上的多个js事件处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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