jQuery: Как реализовать "hasParent"?
Описание проблемы:
Я использую jQuery и столкнулся с проблемой, связанной с выбором элементов на основе их предков. Методы parent([selector]) и parents([selector]) выбирают только родителей, но мне нужно отобрать элементы, у которых есть определённые предки.
Я знаю, что метод "has" позволяет выбрать элементы с определёнными потомками, но мне нужен эквивалент для предков.
У меня уже есть jQuery объект, состоящий из элементов 2, 3, 4 и 5. Я хочу выбрать именно те элементы, которые имеют родителя с классом "x".
Пример кода:
<ul class="x">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<ul class="y">
<li>4</li>
<li>5</li>
<li>6</li>
</ul>
В этом примере я хочу, чтобы результатом были элементы 2 и 3, так как они имеют родителя с классом "x".
Я уже имею контекст элемента дальше по иерархии, так что провести запрос сверху вниз не получится. Есть ли метод или способ в jQuery, который позволит сделать то, что мне нужно?
Надеюсь, теперь это яснее.
5 ответ(ов)
Для чистого и переиспользуемого решения рассмотрите возможность расширения объекта jQuery.fn с помощью собственного метода, который будет использоваться для определения наличия конкретного предка для любого заданного элемента:
// Расширяем jQuery.fn новым методом
jQuery.extend( jQuery.fn, {
// Имя нашего метода и один параметр (селектора родителя)
within: function( pSelector ) {
// Возвращаем подмножество элементов, используя jQuery.filter
return this.filter(function(){
// Возвращаем true/false в зависимости от наличия в родителе
return $(this).closest( pSelector ).length;
});
}
});
Это создает новый метод $.fn.within, который мы можем использовать для фильтрации результатов:
$("li").within(".x").css("background", "red");
Этот код выбирает все элементы списка в документе, а затем фильтрует только те, которые имеют .x в качестве предка. Поскольку используется jQuery, вы можете передать более сложный селектор:
$("li").within(".x, .y").css("background", "red");
Этот код отфильтрует коллекцию до элементов, которые являются потомками либо .x, либо .y, или обоих.
Пробный пример: http://jsfiddle.net/jonathansampson/6GMN5/
Вы можете использовать следующий код для проверки, если элемент с классом .foo имеет родителя, соответствующего селектору .parentSelector:
if ( $('.foo').parents('.parentSelector').length ) {
// У элемента есть родитель, соответствующий селектору
}
В этом фрагменте кода метод parents() ищет всех предков элемента с классом .foo, которые соответствуют селектору .parentSelector. Если длина результата (т.е. количество найденных предков) больше нуля, это означает, что такой родитель существует.
Если я правильно понял ваш вопрос, то вы можете реализовать это следующим образом:
$.fn.hasAncestor = function(a) {
return this.filter(function() {
return !!$(this).closest(a).length;
});
};
$('.element').hasAncestor('.container').myAction();
В данном примере метод hasAncestor добавляется к jQuery, позволяя вам проверять, есть ли у элемента указанный родитель. Вызов $('.element').hasAncestor('.container') вернет все элементы с классом element, которые имеют родителя с классом container. После этого вы можете вызвать ваш метод myAction() на отфильтрованных элементах.
Вот HTML-код для дополнительного контекста:
<div class="container">
<span>
<strong class="element">strong</strong>
</span>
</div>
Таким образом, если вы хотите узнать, является ли элемент strong потомком div с классом container, этот код будет работать корректно.
В вашем коде используется метод hasParent, который проверяет, есть ли у текущего элемента родительский элемент, соответствующий селектору e. Давайте подробнее рассмотрим ваши примеры.
В первом примере:
$('body').hasParent('html') // trueЗдесь вы проверяете, имеет ли элемент
bodyродителя, который является элементомhtml. Так какbodyдействительно является дочерним элементомhtml, метод возвращаетtrue.Во втором примере:
$('div#myDiv').hasParent($('body')) // trueВ этом коде вы проверяете, есть ли у элемента
divсid="myDiv"родитель, который равен элементуbody. ЕслиmyDivнаходится внутриbody, то вызов также вернетtrue.
Описание метода hasParent:
Ваш метод hasParent реализован с использованием jQuery и выглядит следующим образом:
// проверяет, есть ли у текущего элемента родительский элемент 'e'
$.fn.hasParent = function (e) {
return !!$(this).parents(e).length
}
$(this)ссылается на текущий jQuery объект.this.parents(e)находит всех родительских элементов, соответствующих селекторуe.lengthвернет количество найденных элементов: если оно больше нуля, то это значит, что родитель существует, и метод вернетtrue.
Таким образом, ваш код работает корректно и удобен для использования при проверке иерархии DOM-элементов. Если у вас возникли дополнительные вопросы, не стесняйтесь их задавать!
Вы можете использовать filter напрямую (без функции, вызывающей closest), и это даст вам более высокую производительность. Просто используйте селектор, который соответствует элементам, содержащимся внутри .x:
$("li").filter(".x *")
Это также немного отличается от решений с closest, предложенных другими, так как не будет соответствовать элементу, если он сам имеет данный класс, а только если он находится внутри элемента с этим классом.
Если вы хотите, чтобы соответствовал и сам элемент с классом, то это можно немного изменить:
$("li").filter(".x, .x *")
Пример с применением стиля:
$("li").filter(".x *").css("background", "red");
Вот пример кода:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="x"><li>1</li><li>2</li><li>3</li></ul>
<ul class="y"><li>4</li><li>5</li><li>6</li></ul>
С помощью этого подхода вы сможете эффективно отфильтровать элементы и применить к ним стили.
Как перенаправить на другую веб-страницу?
Прокрутка к элементу с использованием jQuery
Как определить нажатие клавиши Esc?
Как получить данные формы с помощью JavaScript/jQuery?
Как выполнить код после сброса HTML-формы с помощью jQuery?