Фильтрация элементов в наборе jQuery на основе их родительского узла

Предположим, у меня есть два контейнера с одним и тем же CSS, примененным к ним и их подэлементам.

<div class="wrapper">
    <div class="item">item</div>
    <div class="dummy">distrating item</div> <!-- dummy one -->
    <div class="item">item</div>
    <div class="item">item</div>
    ...
</div>
<div class="wrapper">
    <div class="item">item</div>
    <div class="dummy">distrating item</div> <!-- dummy one -->
    <div class="item">item</div>
    <div class="item">item</div>
    ...
</div>

Это конечно на пример. но суть вот в чем. Если я определяю селектор jQuery как:

$(".wrapper .item")

а затем напишите плагин jQuery, который должен что-то делать с этими элементами, но для каждого контейнера, как я могу получить подмножество элементов из всего набора, принадлежащего каждому контейнеру?

$.fn.extend({
    randomize: function() {
        if (this.length > 1)
        {
            var set = this;
            var origSelect = set.selector;
            var containers = this.parent();
            $.each(containers, function() {
                var container = $(this);
                var items = set.filter(?????);
                ....
            });
        }
        return this;
    }
});

На основе данных, которые у меня есть во внутренней функции:

  • полный набор
  • селектор исходного элемента
  • текущий контейнер

Есть ли какой-нибудь селектор jQuery, который может помочь мне получить подмножество элементов из всего набора, принадлежащего определенному элементу.

Первая возможность

Это, конечно, не работает:

$(origSelect, container);

что эквивалентно

$(".wrapper .item", ".wrapper");

потому что класс контейнера CSS является частью исходного селектора. Если бы это было не так, это сработало бы. но я не могу это контролировать.

Вторая возможность

Фильтрация по

container.children();

также завершится ошибкой, так как будут выбраны фиктивные элементы.

Но идея состоит в том, чтобы повторно использовать существующий набор jQuery, что, конечно, быстрее, чем повторный выбор узлов DOM, что делается в обоих случаях.

Итак, в основном я хочу что-то вроде:

set.filter(something);

Но я не знаю, есть ли фильтр для того, что я хочу.


person Robert Koritnik    schedule 29.07.2011    source источник


Ответы (2)


Вы можете сравнить родительские элементы каждого элемента с текущим элементом контейнера:

$.each(containers, function() {
    var container = $(this);
    var items = set.filter(function() {
        return this.parentNode == container[0];
    });
    // ...
});
person Frédéric Hamidi    schedule 29.07.2011
comment
Мммм. Это может быть оно. Почему вы просто не использовали return $(this).closest(container).length == 1? - person Robert Koritnik; 29.07.2011
comment
@ Роберт, хороший момент, я думаю, я был слишком сосредоточен на классе .wrapper :) Я лично думаю, что тестирование length делает намерение несколько менее ясным. - person Frédéric Hamidi; 29.07.2011
comment
Мои элементы всегда являются прямыми дочерними элементами своих контейнеров, потому что контейнеры извлекаются в этой строке var containers = this.parent();, как видно из моего кода. Использование parent(), как вы предложили, может использоваться только при сравнении элементов DOM, поскольку вы можете предоставить селектор строк только для функции parent([selector]). Но это все еще может быть быстрее для тех элементов, которые должны быть отфильтрованы. Особенно, когда элементы находятся глубоко в дереве DOM, поэтому closest будет проходить через множество узлов. - person Robert Koritnik; 29.07.2011
comment
@Robert, на самом деле closest() останавливается на первом элементе, соответствующем селектору (в отличие от parents()). Вы правы насчет вызова parent() в своем вопросе, однако я соответствующим образом обновлю свой ответ. - person Frédéric Hamidi; 29.07.2011
comment
К вашему сведению: я опубликовал общедоступный плагин jQuery, который выполняет транспонирование. Проверьте мой сообщение в блоге об этом и получите код, если он вам нужен. - person Robert Koritnik; 30.07.2011

Вы можете попробовать это

$.fn.extend({
    randomize: function() {
        if (this.length > 1)
        {
            var set = this;
            var origSelect = set.selector;
            var selectorArr = origSelect.split(" ");
            var itemSelector = selectorArr[selectorArr.length - 1];
            var containers = this.parent();
            $.each(containers, function() {
                var container = $(this);
                var items = container.filter(itemSelector);
                ....
            });
        }
        return this;
    }
});
person ShankarSangoli    schedule 29.07.2011
comment
Это не сработает, поскольку все элементы в наборе удовлетворяют условию .item, поэтому ваша фильтрация вернет полный набор. - person Robert Koritnik; 29.07.2011
comment
Нет, не будет работать. container всегда является одним элементом. Фильтровать по нему смысла нет. Вы, вероятно, хотели написать container.children(itemSelector), но в этом случае было бы лучше просто использовать container.children(origSelect), который вернул бы правильные элементы. Проблема в том, что исходный набор не используется повторно, поэтому выбор элементов приходится выполнять заново. - person Robert Koritnik; 29.07.2011
comment
К вашему сведению: я опубликовал общедоступный плагин jQuery, который выполняет транспонирование. Проверьте мой сообщение в блоге об этом и получите код, если он вам нужен. - person Robert Koritnik; 30.07.2011