jQuery: элементы самого высокого уровня, содержащие x

#jquery #jquery-selectors

#jquery #jquery-селекторы

Вопрос:

Я ищу способ выбрать элементы, содержащие определенный элемент, а затем отфильтровать результаты, чтобы получить только самый высокий уровень. Сложно объяснить, но стало проще на примере:

 <div id="one">
    <div id="two">
        <div id="three" class="find-me"></div>
    </div>
</div>
<div id="four">
    <div id="five" class="find-me"></div>
</div>
  

В этом случае я бы хотел, чтобы мой набор содержал # один и # четыре. Если я попытаюсь сделать что-то вроде этого:

 var elements = $('div').has('.find-me');
  

Я получаю элементы # один, # два и # четыре.

Примечание: В данном случае ‘самый высокий уровень’ относится к самому верхнему элементу в первом селекторе $('div') .

Ответ №1:

Ну, определение того, что highest level такое, немного неоднозначно, потому что на практике, если на вашей странице есть что-либо .find-me , родительским элементом самого высокого уровня будет html тег! что бесполезно.

Определив вашу проблему более конкретно, вы можете придумать более четкое определение для этого highest-definition и, например, сказать the farthest div parent et . а для обхода родительских элементов элемента вы можете использовать методы .parents() и .closest() .

 var farthestDiv = $(".find-me").parents("div").last();
  

очевидно, что если у вас более одного появления, find-me вам нужно запустить это в .each() цикле.

смотрите пример здесь: http://jsfiddle.net/GsQDb/3 /

Комментарии:

1. Хороший момент — я предполагаю, что это самый высокий уровень первого набора; $('div') в данном случае. Мне нравится мысль делать это «задом наперед» вот так. Скорость — большая проблема на этой странице (2 мб html для обхода), поэтому было бы интересно узнать разницу в скорости между этим ответом и ответом @karnyj

Ответ №2:

Предполагая, что под «верхним уровнем» вы подразумеваете прямого потомка тега body, вы можете использовать эту строку. Он находит все объекты с .find-me классом, затем выполняет поиск родительского тега, который является потомком тега body (который будет верхнего уровня).

 $(".find-me").parents("body > *")
  

Вы можете увидеть, как это работает здесь: http://jsfiddle.net/jfriend00/9LF6u /

Это имеет следующие преимущества:

  1. Тегом верхнего уровня может быть любой тип тега (не только div)
  2. Это должен быть один из самых быстрых способов сделать это, поскольку он находит .find-me объекты (что будет быстрой внутренней операцией в большинстве браузеров через getElementsByClassName ) и просто поднимается по их родительской иерархии.
  3. Он автоматически обрабатывает дубликаты, поэтому данный элемент верхнего уровня никогда не будет указан более одного раза.
  4. Если когда-либо вы захотите изменить определение верхнего уровня (например, на объект контейнера), вы можете просто изменить селектор, переданный .parents(selector) методу, чтобы отразить это изменение.

Комментарии:

1. Моя неосведомленность об автоматической обработке дубликатов jQuery — вот почему я выбрал обычный маршрут js в своем ответе: P Я преклоняюсь перед мастером

2. Объекты jQuery, созданные с помощью селекторов фильтров, никогда не имеют дубликатов, поскольку большинство методов jQuery заканчиваются внутренним вызовом .unique() , который отфильтровывает дубликаты и расставляет селекторы по порядку документов.

Ответ №3:

используйте filter, чтобы отфильтровать элементы, которые не соответствуют тому, что вы хотите, после вашего первого выбора. пример:

 var elements = $('div.find-me').filter(function(idx){ 
    return !$(this).parents('div.find-me').length;
});
  

Ответ №4:

Это сделает то, что вы хотите, сначала найдет элементы, а затем найдет из них самые высокие элементы и создаст объект jQuery из найденных самых высоких элементов.

 var elements = $('div.find-me'), highest = [];

elements.each( function(){
var parent = this, body = document.body;

    while( parent amp;amp; parent.parentNode !== body ) {
    parent = parent.parentNode;
    }

    if( $.inArray( parent, highest ) < 0 ) {
    highest.push( parent );
    }
});

highest = jQuery( highest );
  

jsfiddle:

http://jsfiddle.net/D3jC8/2/

Ответ №5:

Если вы поместите их все в один большой контейнер div, вы можете использовать:

 $('.container div.find-me').parents($('.container').children());
  

Это ДОЛЖНО сработать, хотя у меня нет возможности протестировать это прямо сейчас.

Дайте мне знать, если нет, поскольку существуют и более сложные решения.

Ответ №6:

Можете ли вы назначить класс большинству верхних разделов? Если это так, вы можете сделать что-то вроде этого:

 var elements = $("div.topMost").has(".find-me");
  

Ответ №7:

 $(".find-me").map(function() {
  return $(this).parents("div").last().get();
});