JQuery: более одного обработчика для одного и того же события


137

Что произойдет, если я назначу два обработчика событий одному и тому же событию для одного и того же элемента?

Например:

var elem = $("...")
elem.click(...);
elem.click(...);

Последний обработчик "побеждает" или оба обработчика будут запущены?

Ответы:


168

Оба обработчика будут работать, модель событий jQuery допускает несколько обработчиков для одного элемента, поэтому более поздний обработчик не переопределяет более старый обработчик.

Обработчики будут выполняться в том порядке, в котором они были связаны .


1
что происходит с родным способом? а откуда родной знает как удалить конкретную?
SuperUberDuper

1
Согласно DOM Level 3 (ссылаясь на спецификацию HTML 5), обработчики событий выполняются в том порядке, в котором они зарегистрированы - w3.org/TR/DOM-Level-3-Events/#event-phase и w3.org/TR/ 2014 / REC-html5-20141028 /… . Обработчики событий можно удалить, передав ссылку на зарегистрированный обработчик
Russ Cam

@RussCam, что произойдет, если один и тот же обработчик будет связан более одного раза, скажем, просто jQuery('.btn').on('click',handlerClick);вызывается в разных местах без .offкакого-либо другого действия?
techie_28

Обратите внимание, что для jQueryUI widgetfactory виджетов это не так, если вы установите обработчик в качестве опции. Для вызова как старого, так и нового обработчика необходимо использовать bindметод. Подробности смотрите здесь: learn.jquery.com/jquery-ui/widget-factory/…
Майкл Шепер

@MichaelScheper не стесняйтесь редактировать ответ и обновлять его дополнительной информацией
Russ Cam

36

Предположим, что у вас есть два обработчика, f и g , и вы хотите убедиться, что они выполняются в известном и фиксированном порядке, а затем просто инкапсулировать их:

$("...").click(function(event){
  f(event);
  g(event);
});

Таким образом, существует (с точки зрения jQuery) только один обработчик, который вызывает f и g в указанном порядке.


3
+1, инкапсуляция внутри функции - путь. И даже лучшая условная логика может содержаться внутри функции-обработчика, чтобы управлять событиями, которые запускаются.
Гордон Поттер

Коллекция обработчиков, чья последовательность определяется программно.
Аарон Бленкуш

17

.bind () запускается в том порядке, в котором он был связан :

Когда событие достигает элемента, запускаются все обработчики, связанные с этим типом события для элемента. Если зарегистрировано несколько обработчиков, они всегда будут выполняться в том порядке, в котором они были связаны. После выполнения всех обработчиков событие продолжается по обычному пути распространения события.

Источник: http://api.jquery.com/bind/

Поскольку другие функции jQuery (например, .click()) являются ярлыками .bind('click', handler), я бы предположил, что они также запускаются в порядке их привязки.


11

Вы должны быть в состоянии использовать цепочку для выполнения событий в последовательности, например:

$('#target')
  .bind('click',function(event) {
    alert('Hello!');
  })
  .bind('click',function(event) {
    alert('Hello again!');
  })
  .bind('click',function(event) {
    alert('Hello yet again!');
  });

Я думаю, что код ниже делает то же самое

$('#target')
      .click(function(event) {
        alert('Hello!');
      })
      .click(function(event) {
        alert('Hello again!');
      })
      .click(function(event) {
        alert('Hello yet again!');
      });

Источник: http://www.peachpit.com/articles/article.aspx?p=1371947&seqNum=3

TFM также говорит:

Когда событие достигает элемента, запускаются все обработчики, связанные с этим типом события для элемента. Если зарегистрировано несколько обработчиков, они всегда будут выполняться в том порядке, в котором они были связаны. После выполнения всех обработчиков событие продолжается по обычному пути распространения события.


1
Ни этот код, ни эта статья не определяют порядок выполнения обработчика. Да, это порядок, в котором будет происходить привязка события , но порядок вызова обработчиков событий по-прежнему официально не определен.
Crescent Fresh

эхх? А как насчет «Теперь, когда происходит событие click, будет вызван первый обработчик события, затем второе, а затем третье». неясно?
anddoutoi

и да, я знаю, что официальные отчеты не определяют это, и PPK уже доказал, что выполнение события является случайным, но, возможно, jQuery исправил это ^^
anddoutoi

Ааа, пропустил это предложение. На самом деле автор дезинформирован. jQuery не «исправил» это. Поскольку спецификация формально не определяет порядок, технически ничего не нужно исправлять.
Crescent Fresh

5
@CrescentFresh: Извините за столь поздний ответ, я только что увидел вопрос, но я бы хотел, чтобы вы When an event reaches an element, all handlers bound to that event type for the element are fired. If there are multiple handlers registered, they will always execute in the order in which they were bound. After all handlers have executed, the event continues along the normal event propagation path.
указали

2

Оба обработчика вызываются.

Вы можете подумать о привязке встроенного события (например "onclick=..."), где большим недостатком является только один обработчик события.

JQuery соответствует модели регистрации событий DOM уровня 2 :

Модель событий DOM позволяет регистрировать несколько прослушивателей событий в одной EventTarget. Для этого прослушиватели событий больше не сохраняются как значения атрибутов.


@Rich: заказ официально не определен.
Crescent Fresh

2

Сделал это успешно, используя 2 метода: инкапсуляцию Stephan202 и несколько прослушивателей событий. У меня есть 3 вкладки поиска, давайте определим их идентификаторы входного текста в массиве:

var ids = new Array("searchtab1", "searchtab2", "searchtab3");

Когда содержимое searchtab1 изменяется, я хочу обновить searchtab2 и searchtab3. Сделал это так для инкапсуляции:

for (var i in ids) {
    $("#" + ids[i]).change(function() {
        for (var j in ids) {
            if (this != ids[j]) {
                $("#" + ids[j]).val($(this).val());
            }
        }
    });
}

Несколько слушателей событий:

for (var i in ids) {
    for (var j in ids) {
        if (ids[i] != ids[j]) {
            $("#" + ids[i]).change(function() {
                $("#" + ids[j]).val($(this).val());
            });
        }
    }
}

Мне нравятся оба метода, но программист выбрал инкапсуляцию, однако сработали и несколько слушателей событий. Мы использовали Chrome, чтобы проверить это.


1

Существует обходной путь, гарантирующий, что один обработчик происходит за другим: присоедините второй обработчик к содержащему элементу и дайте событию всплыть. В обработчике, прикрепленном к контейнеру, вы можете посмотреть на event.target и сделать что-нибудь, если он вам интересен.

Грубый, может быть, но это определенно должно работать.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.