Как предотвратить делегированные обработчики на родителя, не предотвращая по умолчанию в jQuery? - PullRequest
1 голос
/ 01 июля 2010

Есть ли способ предотвратить клик из-за <a>, вызывающего делегированные обработчики кликов на его родительском элементе, в то же время позволяя поведению <a> по умолчанию (переход к href).

Вот пример, который иллюстрирует то, что я спрашиваю.

<div class="top">
    <div class="middle">
        <a href="google.com" class="link">link</a>
    </div>
</div>

И мой JavaScript:

$(".top").delegate(".middle", "click", function(event) {
   alert("failure");
});

$(".top").delegate(".link", "click", function(event) {
   // ???
});

В этом случае я хочу перейти на google.com при нажатии на ссылку, но НЕ должен видеть alert("failure") при выходе.

Существует несколько ограничений для решения:

  1. Все обработчики событий должны быть делегированы с $(".top"), поскольку у меня потенциально есть тысячи таких на странице.
  2. Навигация должна выполняться с использованием поведения браузера по умолчанию, а не window.location = $(this).attr("href") или аналогичного

Используя обычную привязку событий, я мог бы сделать e.stopPropagation() в обработчике кликов для <a>, но это не сработает из-за характера делегирования. jQuery предоставляет другой метод с именем .stopImmediatePropagation(), который описывает то, что я хочу (предотвращая другие обработчики на текущем элементе, в данном случае элемент, который содержит делегированные обработчики), но фактически не выполняет этого в этом случае. Это может быть ошибка в .delegate(), я не уверен.

Возвращение false из обработчика щелчка <a> не позволит запустить другой обработчик, но также выполнит .preventDefault(), поэтому браузер не будет перемещаться. В общем, мне интересно, что return false; делает, а e.stopImmediatePropagation(); e.preventDefault(); нет. На основании документов они должны быть эквивалентными.

Для демонстрационной версии приведенного выше кода, вот jsFiddle: http://jsfiddle.net/CHn8x/

1 Ответ

4 голосов
/ 01 июля 2010

event.stopImmediatePropagation() действительно то, что вы ищете, но помните, что порядок имеет значение здесь, так как .delegate() слушает на том же уровне, поэтому вам нужно изменить свои привязки как это:

$(".top").delegate(".link", "click", function(event) {
  event.stopImmediatePropagation();
});
$(".top").delegate(".middle", "click", function(event) {
  if(!event.isPropagationStopped())
    alert("failure");
});

Вот рабочая версия вашего демо с этим изменением

Порядок, с которым вы связываете обработчики, - это порядок, который они будут выполнять, поэтому вам нужно, чтобы обработчик .link выполнил и остановил распространение до того, как запустится другой обработчик, проверяя его с помощью event.isPropagationStopped() или event.isImmediatePropagationStopped().

Обычно это не проблема на различных уровнях, но поскольку .delegate() прослушивает элемент того же , это имеет значение.

...