Напротив jQuery.Closest(Top/Far-Most?)

У меня есть код с большим количеством подменю, которые имеют одно и то же имя класса.

Здесь структура:

.menu
  .sub-menu
  .sub-menu
    .sub-menu
    .sub-menu
  .sub-menu
    .sub-menu
      .elem
      .elem
  .sub-menu

Обратите внимание, что .sub-menu может быть бесконечным, глубоким.

Итак, как мне достичь этого: когда нажата кнопка .elem, я хочу переместить DOM вверх до тех пор, пока не будет достигнут самый верхний .sub-menu и применит к нему стиль. Я знаю .closest() и .parent() и .find(), но я понятия не имею, имеет ли функция jQuery такую ​​функцию, как .topMost(selector)?

Единственный способ, о котором я могу думать, - это, возможно, запустить цикл и пройти через .closest('.sub-menu') нового элемента до тех пор, пока его длина не станет нулевой (родителей с этим классом больше нет, поэтому он должен быть самым верхним). Однако я думаю, что для этого должен быть более практичный подход.

Ответ 1

Предполагая, что "напротив ближайшего" вы хотите "самый дальний" родительский элемент, вы можете использовать parents().last(), например:

$('.elem').click(function() {
    var $topSubMenu = $(this).parents('.sub-menu').last();
});

Обратите внимание: вам нужен последний элемент массива, поскольку jQuery пересекает DOM, поэтому элемент верхнего уровня будет последним в коллекции.

Ответ 2

Вопрос немного вводит в заблуждение, поскольку. closest() может быть неверно истолкован. На самом деле это означает поиск дерева до тех пор, пока не будет найдено первое совпадение. Таким образом, обратное - поиск вниз по дереву, пока не будет найдено совпадение, и этот метод. first().

Чтобы найти всех потомков, можно использовать find(). Противоположностью find() является parents().

ближайший() (все уровни) Для каждого элемента в наборе получите первый элемент, который соответствует селектору, путем тестирования самого элемента и прохождения его предков в дереве DOM.

first() (все уровни) Уменьшите набор согласованных элементов до первого в наборе

родители() (все уровни) Получите предков каждого элемента в текущем наборе согласованных элементов, опционально отфильтрованных селектором.

parent() (только следующий уровень) Получите родительский элемент каждого элемента в текущем наборе согласованных элементов, опционально отфильтрованный селектором.

find() (все уровни) Получают потомки каждого элемента в текущем наборе согласованных элементов, фильтруются селектором, объектом jQuery или элементом.

Ответ 3

Здесь решение только для JavaScript, основанное на polyfill для closest().

function furthest(s) {
    var el = this.parentElement || this.parentNode;
    var anc = null;

    while (el !== null && el.nodeType === 1) {
        if (el.matches(s)) anc = el;
        el = el.parentElement || el.parentNode;
    }
    return anc;
}