高效,简洁的方式来find下一个匹配的兄弟姐妹?

坚持使用官方的jQuery API,是否有一种更简洁,但并不低效的方式来find与给定select器匹配的元素的下一个兄弟,而不是使用nextAll :first伪类?

当我说官方API时,我的意思是不要黑客内部,直接去Sizzle,在插件中添加一个插件等等。(如果我最终必须这样做,那就这么做吧,但这不是这个问题。 )

例如,给定这种结构:

 <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 (也许在一个click处理程序,无论),并希望find下一个匹配select器“div.foo”的兄弟div,我可以这样做:

 var nextFoo = $(this).nextAll("div.foo:first"); 

…这是行得通的(如果我以“Five”开头,比如跳过“Six”和“Seven”,为我find“Eight”),但是它很笨重,如果我想匹配任何几个select器,它变得很笨重。 (当然,这比原始的DOM循环会更简洁…)

我基本上想要:

 var nextFoo = $(this).nextMatching("div.foo"); 

nextMatching可以接受所有select器。 我总是感到惊讶, 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可以把整个事情交给Sizzle,Sizzle已经彻底优化了。 上面的天真循环创build并抛出各种各样的临时对象,并且每次都要重新parsingselect器,没有太大的惊喜。

当然,我不能只是抛出:first是:

 jQuery.fn.nextMatching = function(selector) { return this.nextAll(selector + ":first"); // <== WRONG }; 

…因为虽然这将使用简单的select器,如“div.foo”,它会失败,我说的“任何几个”选项,如说“div.foo,div.bar”。

编辑 :对不起,应该说:最后,我可以使用.nextAll() ,然后对结果使用.nextAll() ,但然后jQuery将不得不访问所有的兄弟姐妹只是为了find第一个。 我希望它在比赛中停止,而不是完整的列表,这样可以抛弃所有的结果,但第一次。 (虽然它似乎发生得非常快,请参阅前面链接速度比较中的最后一个testing用例。)

提前致谢。

您可以将多重select器传递给.nextAll()并在结果上使用.nextAll() ,如下所示:

 var nextFoo = $(this).nextAll("div.foo, div.something, div.else").first(); 

编辑:只是为了比较,在这里它被添加到testing套件: http : //jsperf.com/jquery-next-loop-vs-nextall-first/2这种方法是如此之快,因为它是一个简单的组合交付.nextAll()select器在可能的情况下(每个当前浏览器)closures到本地代码,只是采取第一个结果集….比任何循环,你可以完全用JavaScript做的更快。

如何使用first一种方法:

 jQuery.fn.nextMatching = function(selector) { return this.nextAll(selector).first(); } 

编辑,更新

使用下一个兄弟select器(“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>