Эффективный, лаконичный способ найти следующего подходящего брата?
придерживаясь официального API jQuery, есть ли более сжатый, но не менее эффективный способ найти следующий брат элемента, который соответствует данному селектору, кроме использования nextAll
С :first
псевдо-класс?
когда я говорю официальный API, я имею в виду не взламывать внутренние устройства, идя прямо шипеть, добавляя плагин в микс и т. д. (Если мне придется это сделать, пусть будет так, но это не то, что этот вопрос.)
например, учитывая это структура:
<div>One</div>
<div class='foo'>Two</div>
<div>Three</div>
<div class='foo'>Four</div>
<div>Five</div>
<div>Six</div>
<div>Seven</div>
<div class='foo'>Eight</div>
если у меня есть div
на this
(возможно, в click
обработчик, что угодно) и хотите найти следующий брат div, который соответствует селектору "div.фу", я могу это сделать:
var nextFoo = $(this).nextAll("div.foo:first");
...и это работает (если я начну с "Пять", например, он пропускает "шесть" и "семь" и находит "восемь" для меня), но он неуклюжий, и если я хочу соответствовать первому из нескольких селекторов, он становится намного более неуклюжим. (Конечно, это много более кратким чем будет сырой цикл DOM...)
я в принципе хочу:
var nextFoo = $(this).nextMatching("div.foo");
...где nextMatching
смогите признавать полный диапасон селекторов. Я всегда удивляюсь, что next(selector)
не делает этого, но это не так, и документы ясно, что он делает, так что...
я всегда могу написать его и добавить, хотя если я это сделаю и придерживаюсь опубликованного API, все становится довольно неэффективным. Например, наивный next
петли:
jQuery.fn.nextMatching = function(selector) {
var match;
match = this.next();
while (match.length > 0 && !match.is(selector)) {
match = match.next();
}
return match;
};
...Это заметно медленнее чем nextAll("selector:first")
. И это неудивительно,nextAll
может передать все это шипеть, и шипение было тщательно оптимизировано. Наивный цикл выше создает и выбрасывает всевозможные временные объекты и должен каждый раз повторно анализировать селектор, не удивительно, что он медленный.
и конечно, я не могу просто бросить :first
на конце:
jQuery.fn.nextMatching = function(selector) {
return this.nextAll(selector + ":first"); // <== WRONG
};
...потому что пока что будет работать с простыми селекторами например, " div.foo", он потерпит неудачу с" любым из нескольких "вариантов, о которых я говорил, например," div.фу, разд.бар."
Edit: извините, должен был сказать: Наконец, я мог бы просто использовать .nextAll()
и затем использовать .first()
по результату, но тогда jQuery придется посетить всех братьев и сестер, чтобы найти первого. Я бы хотел, чтобы он остановился, когда он получает матч, а не проходил через полный список, чтобы он мог выбросить все результаты, кроме первого. (Хотя это, кажется, происходит действительно быстро; смотрите последний тестовый случай в сравнение скорости связаны ранее.)
спасибо заранее.
3 ответа:
вы можете пройти множественный селектор до
.nextAll()
и использовать.first()
на результат, вот так:var nextFoo = $(this).nextAll("div.foo, div.something, div.else").first();
Edit: просто для сравнения, здесь он добавляется в набор тестов:http://jsperf.com/jquery-next-loop-vs-nextall-first/2 Этот подход намного быстрее, потому что это простая комбинация передачи
.nextAll()
селектор выключен в машинный код, когда это возможно (каждый текущий браузер) и просто принимает первый из результирующего набора....путь быстрее, чем любой цикл вы можете сделать чисто в JavaScript.
Как насчет использования
first
способ:jQuery.fn.nextMatching = function(selector) { return this.nextAll(selector).first(); }
Редактировать, Обновляется!--13-->
использование селектор следующих братьев и сестер ("prev ~ siblings")
jQuery.fn.nextMatching = function nextMatchTest(selector) { return $("~ " + selector, this).first() };
http://jsperf.com/jquery-next-loop-vs-nextall-first/10
jQuery.fn.nextMatching = function nextMatchTest(selector) { return $("~ " + selector, this).first() }; var nextFoo = $("div:first").nextMatchTest("div.foo"); console.log(nextFoo)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script> <div>One</div> <div class='foo'>Two</div> <div>Three</div> <div class='foo'>Four</div> <div>Five</div> <div>Six</div> <div>Seven</div> <div class='goo'>Eight</div>
Примечание, еще не добавлено или не опробовано в тесте сравнения. Не уверен, если на самом деле более эффективным, чем
.nextAll()
реализация. Часть пытается разобрать строковый аргумент селектора, имеющий несколько разделенных запятымиselector
' s . Возвращает.first()
элемент одиночных или разделенных запятыми селекторов, предоставленных в качестве аргумента, илиthis
элемент, если нет