可以说我有一个Web应用程序,该应用程序的页面可能包含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 Universe中,此版本必须从1.8版开始以不同的方式实现。以下发行说明来自jQuery博客:
.data(“ events”):jQuery将其与事件相关的数据存储在每个元素上名为(等待)事件的数据对象中。这是一个内部数据结构,因此在1.8中,它将从用户数据名称空间中删除,因此不会与同名项目冲突。仍然可以通过jQuery._data(element,“ events”)访问jQuery的事件数据。
我们确实完全控制了处理程序在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);
随着时间的流逝,考虑一下您的项目。代码丑陋且难以阅读!原因简单总是更好。如果您有10个bindAtTheStart,则可能没有错误。如果您有100 bindAtTheStart,您真的确定可以使其顺序正确吗?
因此,如果必须将多个相同的事件绑定。我认为最好的方法是控制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引入了promises,这是我见过的最简单的实现,用于控制执行顺序。完整文档位于http://api.jquery.com/jquery.when/
$.when( $('#myDiv').css('background-color', 'red') )
.then( alert('hi!') )
.then( myClickFunction( $('#myID') ) )
.then( myThingToRunAfterClick() );
文章标签:events , javascript , jquery
版权声明:本文为原创文章,版权归 javascript 所有,欢迎分享本文,转载请保留出处!
评论已关闭!