jQuery 找到下一个匹配兄弟的高效、简洁的方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4933236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Efficient, concise way to find next matching sibling?
提问by T.J. Crowder
Sticking to the official jQuery API, is there a more concise, but not less efficient, way of finding the next sibling of an element that matches a given selector other than using nextAll
with the :first
pseudo-class?
坚持官方的jQuery API,有没有更简洁,但不是低效率,发现比其他指定选择相匹配的元素的下一个兄弟的方式nextAll
与:first
伪类?
When I say official API, I mean not hacking internals, going straight to Sizzle, adding a plug-in into the mix, etc. (If I end up having to do that, so be it, but that's not what this question is.)
当我说官方 API 时,我的意思是不要破解内部结构,直接使用 Sizzle,在混合中添加插件等(如果我最终不得不这样做,那就这样吧,但这不是这个问题的意思。 )
E.g, given this structure:
例如,给定这个结构:
<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>
If I have a div
in this
(perhaps in a click
handler, whatever) and want to find the next sibling div that matches the selector "div.foo", I can do this:
如果我有一个div
in this
(可能在一个click
处理程序中,无论如何)并且想要找到与选择器“div.foo”匹配的下一个同级 div,我可以这样做:
var nextFoo = $(this).nextAll("div.foo:first");
...and it works (if I start with "Five", for instance, it skips "Six" and "Seven" and finds "Eight" for me), but it's clunky and if I want to match the first of any of several selectors, it gets a lot clunkier. (Granted, it's a lotmore concise than the raw DOM loop would be...)
...它有效(例如,如果我以“五”开头,它会跳过“六”和“七”并为我找到“八”),但它很笨重,如果我想匹配任何一个中的第一个几个选择器,它变得更加笨拙。(当然,这是一个很多更简洁比原始DOM循环将是...)
I basically want:
我基本上想要:
var nextFoo = $(this).nextMatching("div.foo");
...where nextMatching
can accept the full range of selectors. I'm always surprised that next(selector)
doesn't do this, but it doesn't, and the docs are clear about what it does, so...
...哪里nextMatching
可以接受全范围的选择器。我总是很惊讶next(selector)
它没有这样做,但它没有,而且文档很清楚它的作用,所以......
I can always write it and add it, although if I do that and stick to the published API, things get pretty inefficient. For instance, a naïve next
loop:
我总是可以编写并添加它,但如果我这样做并坚持使用已发布的 API,事情就会变得非常低效。例如,一个简单的next
循环:
jQuery.fn.nextMatching = function(selector) {
var match;
match = this.next();
while (match.length > 0 && !match.is(selector)) {
match = match.next();
}
return match;
};
...is markedlyslowerthan nextAll("selector:first")
. And that's not surprising, nextAll
can hand the whole thing off to Sizzle, and Sizzle has been thoroughly optimized. The naïve loop above creates and throws away all sorts of temporary objects and has to re-parse the selector every time, no great surprise it's slow.
...明显慢于nextAll("selector:first")
. 这并不奇怪,nextAll
可以将整个事情交给 Sizzle,而 Sizzle 已经得到了彻底的优化。上面的简单循环创建并丢弃了各种临时对象,并且每次都必须重新解析选择器,它很慢也就不足为奇了。
And of course, I can't just throw a :first
on the end:
当然,我不能只:first
在最后抛出一个:
jQuery.fn.nextMatching = function(selector) {
return this.nextAll(selector + ":first"); // <== WRONG
};
...because while that will work with simple selectors like "div.foo", it will fail with the "any of several" option I talked about, like say "div.foo, div.bar".
...因为虽然这适用于像“div.foo”这样的简单选择器,但它会因我谈到的“任何一个”选项而失败,比如说“div.foo,div.bar”。
Edit: Sorry, should have said: Finally, I could just use .nextAll()
and then use .first()
on the result, but then jQuery will have to visit all of the siblings just to find the first one. I'd like it to stop when it gets a match rather than going through the full list just so it can throw away all results but the first. (Although it seems to happen reallyfast; see the last test case in the speed comparisonlinked earlier.)
编辑:对不起,应该说:最后,我可以使用.nextAll()
然后.first()
在结果上使用,但是 jQuery 将不得不访问所有兄弟姐妹才能找到第一个。我希望它在匹配时停止,而不是遍历完整列表,这样它就可以丢弃除第一个之外的所有结果。(虽然它似乎发生得非常快;请参阅前面链接的速度比较中的最后一个测试用例。)
Thanks in advance.
提前致谢。
回答by Nick Craver
You can pass a multiple selectorto .nextAll()
and use .first()
on the result, like this:
您可以将多个选择器传递给.nextAll()
并.first()
在结果上使用,如下所示:
var nextFoo = $(this).nextAll("div.foo, div.something, div.else").first();
Edit:Just for comparison, here it is added to the test suite: http://jsperf.com/jquery-next-loop-vs-nextall-first/2This approach is so much faster because it's a simple combination of handing the .nextAll()
selector off to native code when possible (every current browser) and just taking the first of the result set....wayfaster than any looping you can do purely in JavaScript.
编辑:只是为了比较,这里将它添加到测试套件中:http: //jsperf.com/jquery-next-loop-vs-nextall-first/2这种方法要快得多,因为它是处理.nextAll()
选择器关闭到本机代码时可能(每当前的浏览器),只是采取的第一个结果集的....方式比任何循环,你可以在JavaScript纯粹做得更快。
回答by lonesomeday
How about using the first
method:
如何使用该first
方法:
jQuery.fn.nextMatching = function(selector) {
return this.nextAll(selector).first();
}
回答by guest271314
Edit, Updated
编辑、更新
Utilizing Next Siblings Selector (“prev ~ siblings”)
jQuery.fn.nextMatching = function nextMatchTest(selector) {
return $("~ " + selector, this).first()
};
http://jsperf.com/jquery-next-loop-vs-nextall-first/10
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>
Note, Not yet added to or tried at comparison test. Not certain if actually more efficient than .nextAll()
implementation. Piece attempts to parse selector string argument having multiple comma-separated selector
's . Returns .first()
element of single or comma-separated selectors provided as argument , or this
element if no selector
argument provided to .nextMatchTest()
. Appear to return same results at chrome 37 , ie11
注意,尚未添加或尝试比较测试。不确定实际上是否比.nextAll()
实施更有效。Piece 尝试解析具有多个逗号分隔的selector
's 的选择器字符串参数。返回.first()
作为参数提供的单个或逗号分隔的选择器的this
元素,如果没有selector
提供参数,则返回元素.nextMatchTest()
。似乎在 chrome 37 ,ie11 返回相同的结果
v2
v2
$.fn.nextMatching = function (selector) {
var elem = /,/.test(selector) ? selector.split(",") : selector
, sel = this.selector
, ret = $.isArray(elem) ? elem.map(function (el) {
return $(sel + " ~ " + $(el).selector).first()[0]
}) : $(sel + " ~ " + elem).first();
return selector ? $(ret) : this
};
$.fn.nextMatching = function (selector) {
var elem = /,/.test(selector) ? selector.split(",") : selector
, sel = this.selector
, ret = $.isArray(elem) ? elem.map(function (el) {
return $(sel + " ~ " + $(el).selector).first()[0]
}) : $(sel + " ~ " + elem).first();
return selector ? $(ret) : this
};
var div = $("div:first")
, foo = div.nextMatching()
, nextFoo = div.nextMatching("div.foo")
, nextFooMultiple = div.nextMatching("div.foo, div.goo");
nextFooMultiple.css("color", "green");
nextFoo.css("color", "blue");
console.log(foo);
<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>