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?