假设我有一个Web应用程序,其中有一个页面可能包含4个脚本块 - 我写的脚本可以在其中一个块中找到,但我不知道哪个是由控制器处理的.
我将一些onclick
事件绑定到一个按钮,但我发现它们有时按照我没想到的顺序执行.
有没有办法确保订单,或者你过去如何处理这个问题?
如果顺序很重要,您可以创建自己的事件并绑定回调以在其他回调触发这些事件时触发.
$('#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插件,它绑定一个总是在任何其他人之前触发的事件监听器:
**更新内联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()和其他相关函数之外的任何方式绑定的事件侦听器之外,它不一定会被触发.
调用绑定回调的顺序由每个jQuery对象的事件数据管理.没有任何函数(我知道)允许您直接查看和操作该数据,您只能使用bind()和unbind()(或任何等效的辅助函数).
Dowski的方法是最好的,您应该修改各种绑定回调以绑定到自定义事件的有序序列,并将"first"回调绑定到"real"事件.这样,无论它们绑定的顺序如何,序列都将以正确的方式执行.
我能看到的唯一选择是你真的,真的不想考虑的事情:如果你知道函数的绑定语法可能已经绑定在你之前,尝试解除所有这些函数的绑定,然后重新绑定它们以适当的顺序自己.这只是在寻找麻烦,因为现在你有重复的代码.
如果jQuery允许您简单地更改对象的事件数据中绑定事件的顺序,但是没有编写一些代码来挂钩到似乎不可能的jQuery核心,那将会很酷.并且可能存在允许我没有想到的含义,所以也许这是故意的遗漏.
请注意,在jQuery Universe中,必须以1.8版本的方式实现这一点.以下发行说明来自jQuery博客:
.data("events"):jQuery将其事件相关数据存储在每个元素上名为(等待它)事件的数据对象中.这是一个内部数据结构,因此在1.8中,这将从用户数据名称空间中删除,因此它不会与同名项目冲突.jQuery的事件数据仍然可以通过jQuery._data访问(元素,"事件")
我们可以完全控制处理程序在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();