jQuery 单个元素上的多个 JS 事件处理程序
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/17352104/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Multiple JS event handlers on single element
提问by rhinds
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.
我正在使用一个现有的网络应用程序,在应用程序中有各种不同形式的提交按钮,一些使用常规的 http post,一些定义一个 onClick 函数,还有一些使用类上的类将 js 事件处理程序绑定到按钮元素。
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?
示例场景是我想向这些按钮添加一个类,将它们全部绑定到一个常见的 js 函数,该函数只是将使用情况记录到某些 api 中。是否存在因为表单提交已离开页面而未调用日志记录功能的风险?
I've not done loads of js development, and I could test this 100 times over and just get lucky with it firing.
我没有做过大量的 js 开发,我可以测试这个 100 次,并且很幸运能成功。
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?
如上所示,我可以绑定多个事件,在这个例子中,只是定向到另一个 url,但这可能是一个form.submit()
等等。在我的测试中,警报总是首先被触发,但我只是在竞争条件下走运吗?
回答by Elias Van Ootegem
In JS, you don't reallyhave control over what order the event handlers are called, but with careful delegation and well-placed listeners, it is possible.
在 JS 中,您无法真正控制调用事件处理程序的顺序,但是通过仔细的委派和位置合理的侦听器,这是可能的。
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 priorto a listener that has been attached to the element itself.
委托是事件模型最强大的功能之一。你可能知道也可能不知道:在 JS 中,一个事件被传递到 dom 的顶部,从那里它向下传播到应该应用事件的元素。因此,按理说,附加到全局对象的事件侦听器将在已附加到元素本身的侦听器之前调用其处理程序。
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 ischanged 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:
现在,这个处理程序将在窗口级别的侦听器调用它的助手之后被调用。这一次,如果被点击的元素没有类,或者元素是一个链接,事件就会改变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);
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.
在这里,通过调用stopPropagation
,事件被终止。除非事件已经改变,否则它不能进一步向下传播到它的目标。如果没有,事件对象会在 DOM 中进一步向下传播,就好像什么都没发生一样。
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).
一旦到达目标节点,事件就进入第二阶段:冒泡阶段。它不是向下传播到 DOM 的深处,而是爬回顶层(一直到全局对象,它被调度到那里......它从哪里来等等)。
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.
这里有很多方便且清晰的图表。我不能说它比好的 'ol quirksmode 更好,所以我建议你阅读他们在那里说的话。
Bottom line: when dealing with 2 event listeners, attach them both on a different level to sort-of queue them the way you like.
底线:在处理 2 个事件侦听器时,将它们附加在不同的级别上,以按照您喜欢的方式对它们进行排序。
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
就是这样,我要睡觉了,希望我说得有道理
回答by Alex Wayne
jQuery makes this easy.
jQuery 使这变得容易。
$(document).on('click', '.someclass', function() {
doStuff();
});
$(document).on('click', '.someclass', function() {
doMoreStuff();
});
Handlers then both will fire on click. jQuery keeps a queue of handers for you. And handles document clicks that match a selector of your choice so that they can be triggered no matter when your buttons are created.
处理程序然后两者都将在点击时触发。jQuery 为您保留一个处理程序队列。并处理与您选择的选择器匹配的文档点击,以便无论何时创建按钮都可以触发它们。
回答by Ville Myrskyneva
I am/was having a similar issue as this. However I can not affect the order of/delegate the pre-existing 'click' events (added by Wicket framework). But I still need to execute a new custom event beforeany of the 'click' or 'change' events handled by the framework.
我/曾经遇到过类似的问题。但是,我无法影响/委托预先存在的“点击”事件(由 Wicket 框架添加)的顺序。但是我仍然需要在框架处理的任何“单击”或“更改”事件之前执行一个新的自定义事件。
Luckily there are several events that are actually executed in order. The 'mousedown' and the 'mouseup' happens to happen before the 'click'.
http://en.wikipedia.org/wiki/DOM_events
幸运的是,有几个事件实际上是按顺序执行的。'mousedown' 和 'mouseup' 恰好发生在 'click' 之前。
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
});
This will allow the logging to be done (e.g. via ajax) before the actual event is executed e.g. a page change via (ajax) link.
这将允许在执行实际事件之前完成日志记录(例如通过 ajax),例如通过(ajax)链接更改页面。
Of course you may need to have more sophisticated means to detect for what the additional event handling should be done, but you can use for example the 'target' information for this. => This script monitors everything on the page, as this is how I need this to be done.
当然,您可能需要更复杂的方法来检测应该完成哪些附加事件处理,但您可以为此使用“目标”信息。=> 此脚本监视页面上的所有内容,因为这是我需要完成的操作。