高效,简洁的方式来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>