如何对与 jQuery 绑定的事件进行排序

IT技术 javascript jquery events
2021-01-19 17:16:07

假设我有一个 Web 应用程序,它的页面可能包含 4 个脚本块 - 我编写的脚本可能位于其中一个块中,但我不知道哪个由控制器处理。

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

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

6个回答

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

$('#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;
});

至少是这样的。

如果我们想在绑定代码之前的某个时间点停止为回调传播单击事件,该怎么办?
2021-03-25 17:16:07
我能问一下为什么这是不被接受的吗?当前接受的答案引用我的答案作为最佳方法,所以我有点困惑。:-)
2021-04-02 17:16:07
这适用于 mkoryak 的情况,但不适用于多次调用同一事件。我有一个类似的问题,单个按键以相反的顺序多次触发 $(window).scroll()
2021-04-08 17:16:07

如果您的所有回调始终存在并且您对它们相互依赖感到满意,则 Doowski 的方法是很好的。

但是,如果您希望回调彼此独立,则可以利用冒泡并将后续事件作为委托附加到父元素。父元素上的处理程序将在元素上的处理程序之后触发,一直持续到文档。这非常好,因为您可以使用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 对象做一些聪明的事情。

.delegate不再使用,您现在应该使用.on,但我不知道如何使用on
2021-03-13 17:16:07
该插件必须修复,因为它不再起作用,请参见此处:stackoverflow.com/questions/12214654/...
2021-03-31 17:16:07
如果您想利用冒泡,我认为该事件需要是直接的而不是委托的api.jquery.com/on/#direct-and-delegated-events
2021-04-07 17:16:07
@eric.itzhak 要使 .on() 表现得像旧的 .delegate(),只需为它提供一个选择器。详情请见api.jquery.com/delegate
2021-04-08 17:16:07

我一直试图概括这种过程,但就我而言,我只关心链中第一个事件侦听器的顺序。

如果它有任何用处,这里是我的 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 1.8 这里有一个类似的功能已更新:stackoverflow.com/a/2641047/850782
2021-03-25 17:16:07
这不再起作用,因为它使用了this.data("events"),请参见此处的stackoverflow.com/questions/12214654/...
2021-04-07 17:16:07
需要注意的是,这也仅适用于通过 jQuery 添加的事件。
2021-04-09 17:16:07

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

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

我能看到的唯一替代方法是您真的,真的不想考虑:如果您知道函数的绑定语法可能在您之前已经绑定,请尝试取消绑定所有这些函数,然后重新绑定它们自己按正确的顺序。那只是自找麻烦,因为现在您有重复的代码。

如果 jQuery 允许您简单地更改对象事件数据中绑定事件的顺序,而无需编写一些代码来挂钩 jQuery 核心,这似乎是不可能的,那将会很酷。并且可能有我没有想到的允许这样做的含义,所以这可能是有意的遗漏。

要查看 jquery 绑定到元素的所有事件,请使用 var allEvents = $.data( this, "events" );
2021-04-05 17:16:07

请注意,在 jQuery Universe 中,从 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();
});