Освоение всплывающих событий

Допустим, у нас есть такая структура HTML

<div id="container">
    <div id="nested">
        <span id="someElement"></span>
    </div>
</div>

... и наша цель - иметь прослушиватель событий на #container только! Итак, привязываем слушателя (код jQuery)

$("#container").on('click', function(event) {
    alert("container was clicked");
});

Это, конечно, работает, но моя проблема с этим подходом заключается в том, что, поскольку события обычно всплывают, этот слушатель также сработает, если мы на самом деле нажмем #nested или #someElement. Мое текущее решение только обрабатывать щелчок при нажатии на #container состоит в том, чтобы сравнить this с event.target

$("#container").on('click', function(event) {
    if(this === event.target) {
        alert("container was clicked");
    }
});

Мой вопрос: считается ли это «лучшей практикой»? Есть ли лучший способ с помощью jQuery добиться того же результата «из коробки»?

Пример в действии: http://jsfiddle.net/FKX7p/


person Andre Meinhold    schedule 17.09.2012    source источник
comment
ИМО, это лучшая практика.   -  person VisioN    schedule 17.09.2012
comment
@jSang: На самом деле у внутренних элементов нет слушателей по щелчку. Это считается лучшей практикой? привязать каждый элемент, чтобы остановить распространение?   -  person Andre Meinhold    schedule 17.09.2012
comment
Я тоже не вижу лучшего подхода, на самом деле, я собирался опубликовать это как ответ, пока не увидел, что у вас уже есть этот код.   -  person Fabrício Matté    schedule 17.09.2012


Ответы (3)


Альтернативный способ предотвращения всплытия событий — использовать event.stopPropagation();

$("#container").on('click', function(event) {
    alert("container was clicked");
})
.children().on('click', function(event) {
    event.stopPropagation();
});

Я думаю, что преимущество использования этого подхода заключается в том, что если вы хотите прикрепить другое событие к вложенному div, вы можете просто использовать

$("#nested").on('click', function(event) {
    event.stopPropagation();
    // some action
});

$("#container").on('click', function(event) {
    alert("container was clicked");
});​
person Mr. 14    schedule 21.09.2012

Я не уверен, какой из них работает быстрее, но логично, что следующий код будет лучше:

$("#container").click(function (e) {
    if (e.target.id && e.target.id !== "container") return false;
});
person Yochai Akoka    schedule 20.09.2012
comment
Теперь я только проверяю идентификатор, со сложными селекторами я не вижу другого пути, кроме как сравнивать объекты - person Yochai Akoka; 20.09.2012

Альтернативное решение:

$("#container").click(function(){
    alert("container was clicked");
}).children().click(function(e) {
    return false;
});

Но ваше решение лучше. jsfiddle.net/FKX7p/2/ (с возвратом false) ИЛИ jsfiddle.net/FKX7p/3/ (с использованием stopPropagation)

Я предпочитаю использовать return в вашем примере (код становится легче читать):

if(this !== event.target) return;
person webdeveloper    schedule 17.09.2012
comment
Кроме того, при необходимости используйте event.CurrentTarget !== event.Target вместо this из-за возможного изменения контекста this при использовании jQuery.proxy: api.jquery.com/jQuery.proxy - person Nope; 17.09.2012
comment
Альтернативное решение хуже, так как добавляет много обработчиков событий. - person naugtur; 19.09.2012
comment
@naugtur Я согласен с вами, но до функции on это решение было популярно. - person webdeveloper; 19.09.2012
comment
если популярный != хорошо, то да ;) Сравнение target и currentTarget намного лучше. (заметьте, я не ставлю вам -1; в основном потому, что я делал подобные вещи) - person naugtur; 20.09.2012
comment
@naugtur Да, ты прав. Хочу отметить, что мне никто не ставит -1 :) - person webdeveloper; 20.09.2012