JQuery: find() до появления определенного порогового элемента

У меня есть вложенная структура таблицы, например

   <table>

       <td id="first">

           <div class="wrapper">
               <input name=1>
           </div>

           <input name=2>

           <table>

               <td id="second">

                   <input name=3>

У меня есть выбор jQuery $("#first"). Я хотел бы пройти и find() всех детей <input>s в этом контексте <td>, но не спускаться во вложенные <table> s.

Мне нужен трюк jQuery, который

  • Будет ли find() все дочерние элементы определенного элемента

  • Снизет n уровней вниз в дереве DOM

  • Но останавливается нисходящий, если встречается определенный элемент (<table>), так что селектор не выбирает входы вложенных таблиц (которые будут обрабатываться отдельно)

  • Может быть любое количество вложенных уровней <table>, поэтому решение должно работать независимо от того, сколько родительских <table> или детей <table> встречается в пределах $( "# first" ) <td> или любой другой <td>

Я проверил другой поиск jQuery до вопросов. У них есть ответы, но похоже, что они не заполняют последние критерии.

Ответ 1

У меня была аналогичная проблема в этом другом вопросе. В конце концов я окончательно выяснил плагин, когда я возвращался туда и обратно, и некоторые люди пытались найти селектор поиска.

ИСПОЛЬЗОВАНИЕ: ExclusiveInputs = $('#first').findExclude('input','table');

// Find-like method which masks any descendant
// branches matching the Mask argument.
$.fn.findExclude = function( Selector, Mask, result){

    // Default result to an empty jQuery object if not provided
    var result = typeof result !== 'undefined' ?
                result :
                new jQuery();

    // Iterate through all children, except those match Mask
    this.children().each(function(){

        var thisObject = jQuery( this );
        if( thisObject.is( Selector ) ) 
            result.push( this );

        // Recursively seek children without Mask
        if( !thisObject.is( Mask ) )
            thisObject.findExclude( Selector, Mask, result );
    });

    return result;
}

(Конденсированная версия):

$.fn.findExclude = function( selector, mask, result )
{
    var result = typeof result !== 'undefined' ? result : new jQuery();
    this.children().each( function(){
        var thisObject = jQuery( this );
        if( thisObject.is( selector ) ) 
            result.push( this );
        if( !thisObject.is( mask ) )
            thisObject.findExclude( selector, mask, result );
    });
    return result;
}

Ответ 2

Обновление: пусть у нас будет еще один вариант.

В принципе, вы хотите сопоставить все элементы <input>, которые являются потомками #first и которые не являются дочерними элементами элементов <td>, вложенными более чем на один уровень под #first.

(Я не уверен в этой последней части under #first, но ее реализация позволяет нам поддерживать элементы <td> выше #first в цепочке предков.)

Технически, один из следующих селекторов должен выполнить ваши требования:

var inputs = $("#first td:not(#first td td) > input");

Если это не работает в вашем браузере (Sizzle должен соответствовать задаче, я думаю, но сложные селектора типа :not() всегда сложны), вы можете делегировать обработку методам jQuery:

var inputs = $("#first td").not("#first td td").children("input");

Оригинальный ответ следует:

Вы можете использовать not(), чтобы исключить элементы <input>, которые имеют более одного предка <td>:

var firstLevelCells = $("#first").find("input").not("td td input");

Ответ 3

eh, у меня есть лучшая идея..

var badTable = "table.bad"; //the one you want to avoid
var $goodInputs = $("#first").find('input').filter(function() {
    return $(this).closest(badTable).length == 0;
});

это может быть или не быть достаточно быстрым для вас. это зависит от вашего DOM, о котором вы не хотите говорить;)

если он медленный, просто напишите код для своего алгоритма вручную. Не существует ярлыка селектора.

Ответ 4

У меня была аналогичная проблема, и мне все еще приходилось делать что-то без цикла расширения или иметь точную структуру DOM. В моем случае у меня уже была ссылка на элемент "#first", который, если вы этого не сделаете, мы могли бы получить его, например, с каждым (даже если это только один объект). Хитрость заключается в том, чтобы вернуться к дереву с родителями и зайти в верхний элемент, чтобы увидеть, есть ли какой-либо промежуточный элемент, удовлетворяющий условию.

Используя сокращенную лямбда-нотацию для функций (как вы можете записать в typescript), это приведет к следующему:

$('#first').each((idx, f) => $(f).find('input').filter((idx2, inp) => $(inp).parentsUntil(f, 'table').length == 0)

Это может быть не самый эффективный способ (поскольку вы сначала выбираете все, чтобы затем выбрасывать элементы, снова создавая DOM-дерево, но он компактен и довольно общий.