1. ホーム
  2. jquery

次に一致する兄弟姉妹を効率よく、簡潔に見つける方法は?

2023-08-22 06:54:17

質問

公式のjQuery APIにこだわると、与えられたセレクタにマッチする要素の次の兄弟を見つけるための、より簡潔で、しかし効率に劣らない方法は 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>

もし私が divthis (おそらく click ハンドラでも何でも)、セレクタ "div.foo" に一致する次の兄弟 div を見つけたい場合、私はこれを行うことができます。

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

...そして、それは動作します(例えば、私が "Five" で始めた場合、それは "Six" と "Seven" をスキップして私のために "Eight" を見つけます)、しかしそれは不格好です、もし私がいくつかのセレクタのうちのどれかにマッチしたい場合、それはもっと不格好になります。(もちろん、これは ロット よりも簡潔です。)

私は基本的に欲しいです。

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 は全部を Sizzle に渡すことができますし、Sizzle は徹底的に最適化されています。上記の素朴なループは、あらゆる種類の一時的なオブジェクトを作成して捨て、セレクタを毎回再パースしなければなりません。

そしてもちろん、私はただ単に :first を末尾につけることもできます。

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

...というのも、これは "div.foo" のような単純なセレクタでは動作しますが、私が話した "any of several" オプション、例えば "div.foo, div.bar" では失敗してしまうからです。

編集 : すみません、そう言うべきでした。最後に、私はちょうど .nextAll() を使って、その後に .first() を使用すると、jQueryは最初の1つを見つけるためにすべての兄弟を訪問しなければなりません。私は、最初のもの以外のすべての結果を捨てることができるように、リスト全体を通過するのではなく、一致したときに停止するようにしてほしいのです。(これは は本当に の最後のテストケースをご覧ください。 速度比較 の最後のテストケースを参照してください)。

よろしくお願いします。

どのように解決するのですか?

を渡すことができます。 複数セレクタ .nextAll() を使用し .first() をつけると、このようになります。

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

編集する 比較のために、ここでテストスイートに追加されます。 http://jsperf.com/jquery-next-loop-vs-nextall-first/2 この方法はとても高速です。というのも、単純な組み合わせで .nextAll() セレクタを可能な限りネイティブコードに渡し (現在のすべてのブラウザ)、結果セットの最初のものを取得するだけの単純な組み合わせだからです...。 方法 は、純粋に JavaScript で実行できるどのようなループよりも高速です。