附加 jQuery 事件处理程序,以便它们首先被触发

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4742610/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-26 17:51:14  来源:igfitidea点击:

Attaching jQuery event handlers so that they are triggered first

jqueryeventsbinding

提问by Jacob

Is there a way to attach a jQuery event handler such that the handler is triggered before any previously-attached event handlers? I came across this article, but the code didn't work because event handlers are no-longer stored in an array, which is what his code expected. I attempted to create a jQuery extension to do what I wanted, but this is not working (the events still fire in the order they were bound):

有没有办法附加 jQuery 事件处理程序,以便在任何先前附加的事件处理程序之前触发该处理程序?我遇到了这篇文章,但代码不起作用,因为事件处理程序不再存储在数组中,这正是他的代码所期望的。我试图创建一个 jQuery 扩展来做我想做的事,但这不起作用(事件仍然按照它们被绑定的顺序触发):

$.fn.extend({
    bindFirst: function(type, handler) {

        var baseType = type;
        var dotIdx = type.indexOf('.');
        if (dotIdx >= 0) {
            baseType = type.substr(0, dotIdx);
        }

        this.each(function() {
            var oldEvts = {};
            var data = $.data(this);
            var events = data.events || data.__events__;
            var handlers = events[baseType];
            for (var h in handlers) {
                if (handlers.hasOwnProperty(h)) {
                    oldEvts[h] = handlers[h];
                    delete handlers[h];
                    // Also tried an unbind here, to no avail
                }
            }

            var self = $(this);
            self.bind(type, handler);

            for (var h in oldEvts) {
                if (oldEvts.hasOwnProperty(h)) {
                    self.bind(baseType, oldEvts[h]);
                }
            }
        });
    }
});

Is there a naturalway to reorder event handling? If there isn't, do you know of technique I could apply? I'm using jQuery 1.4.1, though I'll upgrade if I must.

是否有一种自然的方式来重新排序事件处理?如果没有,你知道我可以应用的技术吗?我使用的是 jQuery 1.4.1,但如果需要我会升级。

采纳答案by user113716

Here's a simple plugin I did a while back. Lets you bind a handler to the beginning of the list. It is very simple, and I wouldn't guarantee that it works with namespaced events or anything terribly fancy.

这是我不久前制作的一个简单插件。允许您将处理程序绑定到列表的开头。它非常简单,我不保证它适用于命名空间事件或任何非常花哨的事情。

For simply binding a single or space separate group of events, it should work.

对于简单地绑定单个或空间独立的事件组,它应该可以工作。

Example:http://jsfiddle.net/gbcUy/

示例:http : //jsfiddle.net/gbcUy/

$.fn.bindUp = function(type, fn) {

    type = type.split(/\s+/);

    this.each(function() {
        var len = type.length;
        while( len-- ) {
            $(this).bind(type[len], fn);

            var evt = $.data(this, 'events')[type[len]];
            evt.splice(0, 0, evt.pop());
        }
    });
};

Or if you wanted to manipulate the Array of handlers in some other manner, just get the handlers for the element you want, and manipulate it however you want:

或者,如果您想以其他方式操作处理程序数组,只需获取所需元素的处理程序,然后根据需要操作它:

Example:http://jsfiddle.net/gbcUy/1/

示例:http : //jsfiddle.net/gbcUy/1/

var clickHandlers = $('img').data('events').click;

clickHandlers.reverse(); // reverse the order of the Array

回答by Jordan Gray

There is a rather nice plugin called jQuery.bind-firstthat provides analogues of the native on, bind, delegateand livemethods which push an event to the top of the registration queue. It also takes account of differences in event registration between 1.7 and earlier versions. Here's how to use it:

有一种称为相当不错的插件jQuery.bind-第一,它提供的天然类似物onbinddelegatelive方法这推动将事件注册队列的顶部。它还考虑了 1.7 和更早版本之间在事件注册方面的差异。以下是如何使用它:

$('button')
    .on     ('click', function() { /* Runs second */ })
    .onFirst('click', function() { /* Runs first  */ });

As with most of these answers, the big disadvantage is that it relies on jQuery's internal event registration logic and could easily break if it changes—like it did in version 1.7! It might be better for the longevity of your project to find a solution that doesn't involve hiHymaning jQuery internals.

与大多数这些答案一样,最大的缺点是它依赖于 jQuery 的内部事件注册逻辑,并且如果它发生变化很容易中断——就像它在 1.7 版中所做的那样!找到一个不涉及劫持 jQuery 内部结构的解决方案可能会更好地延长您的项目的寿命。

In my particular case, I was trying to get two plugins to play nice. I handled it using custom events as described in the documentation for the triggermethod. You may be able to adapt a similar approach to your own circumstances. Here's an example to get you started:

在我的特殊情况下,我试图让两个插件发挥出色。我使用自定义事件处理它,如方法文档中所述trigger。您或许可以根据自己的情况采用类似的方法。这是一个让您入门的示例:

$('button')
    .on('click', function() {
        // Declare and trigger a "before-click" event.
        $(this).trigger('before-click');

        // Subsequent code run after the "before-click" events.
    })
    .on('before-click', function() {
        // Run before the main body of the click event.
    });

And, in case you need to, here's how to set properties on the event object passed to the handler function and access the result of the last before-clickevent to execute:

而且,如果您需要,这里是如何设置传递给处理程序函数的事件对象的属性并访问before-click要执行的最后一个事件的结果:

// Add the click event's pageX and pageY to the before-click event properties.
var beforeClickEvent = $.Event('before-click', { pageX: e.pageX, pageY: e.pageY });
$(this).trigger(beforeClickEvent);

// beforeClickEvent.result holds the return value of the last before-click event.
if (beforeClickEvent.result === 'no-click') return;

回答by Linh Dam

As answered here https://stackoverflow.com/a/35472362/1815779, you can do like this:

如此处回答https://stackoverflow.com/a/35472362/1815779,您可以这样做:

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

Warning: this is notthe recommended way to bind events, other developers may murder you for this.

警告:这不是绑定事件的推荐方式,其他开发人员可能会因此而谋杀您。

回答by roktir

Here's a combination of some prior methods including support for handlers, namespacing, non-jquery bindings, and once support:

这是一些先前方法的组合,包括对处理程序的支持、命名空间、非 jquery 绑定和一次支持:

$.fn.oneFirst = function(event_type, event_callback, handler) {
    return this.bindFirst(event_type, event_callback, handler, "one");
},
$.fn.bindFirst = function(event_type, event_callback, handler, bind_type) {
    var event_types = event_type.split(/\s+/);
    var pos;
    handler = (handler == undefined ? event_callback : handler);
    event_callback = (typeof event_callback == "function" ? {} : event_callback);

    this.each(function() {
        var $this = $(this);
        for (var i in event_types) { // each bound type
            event_type = event_types[i];

            var event_namespace = ((pos = event_type.indexOf(".")) > 0 ? event_type.substring(pos) : "");
            event_type = (pos > 0 ? event_type.substring(0, pos) : event_type);
            var current_attr_listener = this["on" + event_type];

            if (current_attr_listener) { // support non-jquery binded events
                $this.bind(event_type, function(e) {
                    return current_attr_listener(e.originalEvent);
                });
                this["on" + event_type] = null;
            }

            if (bind_type == "one") {
                $this.one(event_type + event_namespace, event_callback, handler);
            }
            else {
                $this.bind(event_type + event_namespace, event_callback, handler);
            }

            var all_events = $.data(this, 'events') || $._data(this).events;
            var type_events = all_events[event_type];
            var new_event = type_events.pop();
            type_events.unshift(new_event);
        }
    });
};

回答by jLuna

In addition to the selected answer, consider it's missing parameters:

除了选定的答案,还要考虑缺少参数:

jQuery.fn.bindUp = function (type, parameters, fn) {
    type = type.split(/\s+/);

    this.each(function () {
        var len = type.length;
        while (len--) {
            if (typeof parameters === "function")
                jQuery(this).bind(type[len], parameters);
            else
                jQuery(this).bind(type[len], parameters, fn);

            var evt = jQuery._data(this, 'events')[type[len]];
            evt.splice(0, 0, evt.pop());
        }
    });
};

回答by dave

@patrick: I've been trying to solve the same problem and this solution does exactly what I need. One minor problem is that your plug-in doesn't handle namespacing for the new event. This minor tweak should take care of it:

@patrick:我一直在尝试解决同样的问题,这个解决方案正是我所需要的。一个小问题是您的插件不处理新事件的命名空间。这个小调整应该解决它:

Change:

改变:

var evt = $.data(this, 'events')[type[len]];

to:

到:

var evt = $.data(this, 'events')[type[len].replace(/\..+$/, '')];

回答by phoenix12

what about this? bind the event and than do this:

那这个呢?绑定事件,然后执行以下操作:

handlers.unshift( handlers.pop() );

回答by onassar

My best attempt.
I had code that was structured as follows:

我最好的尝试。
我的代码结构如下:

var $body = jQuery('body');
$body.on({
    'click': function(event){
    }
});

To then ensure that the callback was the first one called, I used this function:

为了确保回调是第一个调用的,我使用了这个函数:

/**
 * promoteLastEvent
 * 
 * @access  public
 * @param   jQuery $element
 * @param   String eventName
 * @return  void
 */
function promoteLastEvent($element, eventName) {
    var events = jQuery._data($element.get(0), 'events'),
        eventNameEvents = events[eventName],
        lastEvent = eventNameEvents.pop();
    eventNameEvents.splice(1, 0, lastEvent);
};

This is called as follows:

这称为如下:

promoteLastEvent($body, 'click');

It works quite well for me, given my limited use of $.fn.on.

鉴于我对$.fn.on.

回答by Charlie

I create a very simple function to put my click event handler at first position, and all existing click handlers will only be triggered manually.

我创建了一个非常简单的函数来将我的点击事件处理程序放在第一个位置,并且所有现有的点击处理程序只会被手动触发。

$.fn.bindClickFirst = function (eventHandler) {
    var events = $._data($next[0], "events");
    var clickEvtHandlers = [];

    events.click.forEach(function (evt) {
        clickEvtHandlers.push(evt.handler);
    });
    $next.off("click");

    $next.on("click", function () {
        var evtArg = event;
        eventHandler(evtArg, function () {
            clickEvtHandlers.forEach(function (evt) {
                evt(evtArg);
            });
        });
    })
}

And to use the function:

并使用该功能:

$btn.bindClickFirst(function (evt, next) {
    setTimeout(function () {
        console.log("bbb");
        next();
    }, 200)
})