如何订购与jQuery绑定的事件

比方说,我有一个网页应用程序,其中可能包含4个脚本块的页面 – 我写的脚本可能会在其中一个块中找到,但我不知道哪一个,由控制器处理。

我将一些onclick事件绑定到一个按钮上,但是我发现它们有时会以我没有想到的顺序执行。

有没有办法确保秩序,或者你过去是如何处理这个问题的?

我一直在努力推广这种过程,但就我而言,我只关心链中第一个事件监听器的顺序。

如果它有任何用处,这里是我的jQuery插件绑定一个事件监听器,总是触发之前触发:

** 更新内联jQuery的变化(感谢Toskan) **

 (function($) { $.fn.bindFirst = function(/*String*/ eventType, /*[Object])*/ eventData, /*Function*/ handler) { var indexOfDot = eventType.indexOf("."); var eventNameSpace = indexOfDot > 0 ? eventType.substring(indexOfDot) : ""; eventType = indexOfDot > 0 ? eventType.substring(0, indexOfDot) : eventType; handler = handler == undefined ? eventData : handler; eventData = typeof eventData == "function" ? {} : eventData; return this.each(function() { var $this = $(this); var currentAttrListener = this["on" + eventType]; if (currentAttrListener) { $this.bind(eventType, function(e) { return currentAttrListener(e.originalEvent); }); this["on" + eventType] = null; } $this.bind(eventType + eventNameSpace, eventData, handler); var allEvents = $this.data("events") || $._data($this[0], "events"); var typeEvents = allEvents[eventType]; var newEvent = typeEvents.pop(); typeEvents.unshift(newEvent); }); }; })(jQuery); 

注意事项:

  • 这还没有经过充分的测试。
  • 它依赖于jQuery框架的内部没有改变(只测试了1.5.2)。
  • 在事件监听器之前,它不一定会被触发,而事件监听器除了作为源元素的属性或使用jQuery bind()和其他相关的函数以外,并不以任何方式绑定。

如果顺序很重要,您可以创建自己的事件并绑定回调,以在其他回调触发这些事件时触发。

 $('#mydiv').click(function(e) { // maniplate #mydiv ... $('#mydiv').trigger('mydiv-manipulated'); }); $('#mydiv').bind('mydiv-manipulated', function(e) { // do more stuff now that #mydiv has been manipulated return; }); 

至少是这样的。

如果你所有的回调总是存在的话,那么Dowski的方法是很好的,你很高兴他们互相依赖。

如果你希望回调是相互独立的,那么你可以利用冒泡并将后续事件作为委托给父元素。 父元素上的处理程序将在元素上的处理程序之后触发,并继续到文档。 这是相当不错的,因为您可以使用event.stopPropagation()event.preventDefault()等来跳过处理程序并取消或取消操作。

 $( '#mybutton' ).click( function(e) { // Do stuff first } ); $( '#mybutton' ).click( function(e) { // Do other stuff first } ); $( document ).delegate( '#mybutton', 'click', function(e) { // Do stuff last } ); 

或者,如果你不喜欢这个,你可以使用Nick Leaches bindLast插件来强制事件被绑定到最后: https : //github.com/nickyleach/jQuery.bindLast 。

或者,如果你使用的是jQuery 1.5,你也可以用新的Deferred对象做一些巧妙的事情。

绑定回调被调用的顺序由每个jQuery对象的事件数据管理。 没有任何函数(我知道的)允许你直接查看和操作数据,你只能使用bind()和unbind()(或任何等价的帮助函数)。

Dowski的方法是最好的,你应该修改各种绑定回调绑定到一个有序的事件序列,“第一个”回调绑定到“真实”的事件。 这样,无论按照什么顺序绑定,顺序都会以正确的方式执行。

我能看到的唯一选择是你真的不想考虑的东西:如果你知道函数的绑定语法可能已经绑定在你之前,试图解除绑定所有这些函数,然后重新绑定它们按照正确的顺序 这只是要求麻烦,因为现在你有重复的代码。

如果jQuery允许您简单地改变对象事件数据中绑定事件的顺序,而不写一些代码来挂接jQuery内核,这似乎是不可能的。 有可能是允许我没有想到的,所以也许这是一个故意的遗漏。

请注意,在jQuery的宇宙中,这必须与1.8版本不同。 以下发行说明来自jQuery博客:

.data(“events”):jQuery将其事件相关数据存储在每个元素上的一个名为(等待它)的事件的数据对象中。 这是一个内部数据结构,所以在1.8版本中,这将从用户数据名称空间中删除,因此它不会与具有相同名称的项目发生冲突。 jQuery的事件数据仍然可以通过jQuery._data(element,“events”)来访问

我们完全控制了处理程序在jQuery Universe中执行的顺序。 Ricoo在上面指出了这一点。 看起来不像他的回答赢得了很多的爱,但是这个技巧非常得心应手。 例如,考虑一下任何时候你需要在库部件的某个处理器之前执行你自己的处理器,或者你需要有能力有条件地取消对部件处理器的调用:

 $("button").click(function(e){ if(bSomeConditional) e.stopImmediatePropagation();//Don't execute the widget's handler }).each(function () { var aClickListeners = $._data(this, "events").click; aClickListeners.reverse(); }); 
 function bindFirst(owner, event, handler) { owner.unbind(event, handler); owner.bind(event, handler); var events = owner.data('events')[event]; events.unshift(events.pop()); owner.data('events')[event] = events; } 

只是正常绑定处理程序,然后运行:

 element.data('events').action.reverse(); 

例如:

 $('#mydiv').data('events').click.reverse(); 

你可以尝试这样的事情:

 /** * Guarantee that a event handler allways be the last to execute * @param owner The jquery object with any others events handlers $(selector) * @param event The event descriptor like 'click' * @param handler The event handler to be executed allways at the end. **/ function bindAtTheEnd(owner,event,handler){ var aux=function(){owner.unbind(event,handler);owner.bind(event,handler);}; bindAtTheStart(owner,event,aux,true); } /** * Bind a event handler at the start of all others events handlers. * @param owner Jquery object with any others events handlers $(selector); * @param event The event descriptor for example 'click'; * @param handler The event handler to bind at the start. * @param one If the function only be executed once. **/ function bindAtTheStart(owner,event,handler,one){ var eventos,index; var handlers=new Array(); owner.unbind(event,handler); eventos=owner.data("events")[event]; for(index=0;index<eventos.length;index+=1){ handlers[index]=eventos[index]; } owner.unbind(event); if(one){ owner.one(event,handler); } else{ owner.bind(event,handler); } for(index=0;index<handlers.length;index+=1){ owner.bind(event,ownerhandlers[index]); } } 

我有同样的问题,发现这个话题。 上面的答案可以解决这些问题,但我不认为他们是好计划。

让我们想想现实世界。

如果我们使用这些答案,我们必须改变我们的代码。 你必须改变你的代码风格。 像这样的东西:

原版的:

 $('form').submit(handle); 

破解:

 bindAtTheStart($('form'),'submit',handle); 

随着时间的推移,想想你的项目。 代码是丑陋的,难以阅读! anthoer理由很简单总是更好。 如果你有10个bindAtTheStart,它可能没有错误。 如果你有100个bindAtTheStart,你确定你可以保持正确的顺序吗?

所以如果你必须绑定相同的事件multiple.I认为最好的方法是控制js文件或js代码加载顺序。 jquery可以将事件数据作为队列来处理。 该订单是先入先出。 你不需要改变任何代码。 只是改变加载顺序。

这里是我的这个镜头,涵盖了不同版本的jQuery:

 // Binds a jQuery event to elements at the start of the event chain for that type. jQuery.extend({ _bindEventHandlerAtStart: function ($elements, eventType, handler) { var _data; $elements.bind(eventType, handler); // This bound the event, naturally, at the end of the event chain. We // need it at the start. if (typeof jQuery._data === 'function') { // Since jQuery 1.8.1, it seems, that the events object isn't // available through the public API `.data` method. // Using `$._data, where it exists, seems to work. _data = true; } $elements.each(function (index, element) { var events; if (_data) { events = jQuery._data(element, 'events')[eventType]; } else { events = jQuery(element).data('events')[eventType]; } events.unshift(events.pop()); if (_data) { jQuery._data(element, 'events')[eventType] = events; } else { jQuery(element).data('events')[eventType] = events; } }); } }); 

在某些特殊情况下,如果您无法更改点击事件绑定的方式(事件绑定是从其他代码创建的),并且可以更改HTML元素,则可以使用以下解决方案( 警告 :这不是推荐的绑定方式事件,其他开发者可能会为此谋杀你):

 <span onclick="yourEventHandler(event)">Button</span> 

通过这种绑定方式,您的事件处理程序将首先被添加,因此它将被首先执行。

JQuery 1.5引入了promise,这是我见过的控制执行顺序的最简单的实现。 完整的文档在http://api.jquery.com/jquery.when/

 $.when( $('#myDiv').css('background-color', 'red') ) .then( alert('hi!') ) .then( myClickFunction( $('#myID') ) ) .then( myThingToRunAfterClick() );