В случае делегированных обработчиков событий, где у вас может быть что-то вроде этого:
<ul>
<li data-id="1">
<span>Item 1</span>
</li>
<li data-id="2">
<span>Item 2</span>
</li>
<li data-id="3">
<span>Item 3</span>
</li>
<li data-id="4">
<span>Item 4</span>
</li>
<li data-id="5">
<span>Item 5</span>
</li>
</ul>
и ваш код JS примерно так:
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target),
itemId = $target.data('id');
//do something with itemId
});
});
Вы, скорее всего, обнаружите, что itemId равен undefined
, так как содержимое LI заключено в <span>
, что означает, что <span>
, вероятно, будет целью события. Вы можете обойти это с помощью небольшого чека, например:
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target).is('li') ? $(event.target) : $(event.target).closest('li'),
itemId = $target.data('id');
//do something with itemId
});
});
Или, если вы предпочитаете максимизировать удобочитаемость (а также избежать ненужного повторения вызовов-оберток jQuery):
$(document).ready(function() {
$('ul').on('click li', function(event) {
var $target = $(event.target),
itemId;
$target = $target.is('li') ? $target : $target.closest('li');
itemId = $target.data('id');
//do something with itemId
});
});
При использовании делегирования события метод .is()
имеет неоценимое значение для проверки того, что цель вашего события (помимо всего прочего) действительно соответствует вашей цели. Используйте .closest(selector)
для поиска по дереву DOM и .find(selector)
(обычно в сочетании с .first()
, как в .find(selector).first()
) для поиска по нему. Вам не нужно использовать .first()
при использовании .closest()
, поскольку он возвращает только первый соответствующий элемент-предок, а .find()
возвращает всех соответствующих потомков.