querySelectorは直接の子を検索します


95

私はjqueryのような関数を持っています:

function(elem) {
    return $('> someselector', elem);
};

問題は、どうすれば同じことができるのquerySelector()ですか?

問題は、>セレクターでquerySelector()親を明示的に指定する必要があることです。回避策はありますか?


私はあなたにもっとうまくいくかもしれない答えを追加しました、私に知らせてください;)
csuwldcat '29

回答:


118

完全な答えではありませんが、IEを除くほとんどのブラウザー(デスクトップとモバイルの両方)ですでに利用可能なW3C Selector API v.2に注意する必要があります(Edgeがサポートしているようです)。完全なサポートリストを参照してください

function(elem) {
  return elem.querySelectorAll(':scope > someselector');
};

12
これが正解です。ただし、ブラウザのサポートには制限があり、使用する場合はシムが必要になります。私が建てscopedQuerySelectorShimを、この目的のために。
lazd 2014年


6
実際に:scopeは、まだdrafts.c​​sswg.org/selectors-4/#the-scope-pseudoで指定されています。これまでのところ、<style scoped>削除されたのは属性のみです。それ:scopeが削除にもつながるかどうかは不明です(これ<style scoped>はの重要な使用例でした:scope)。
John Mellor 2016

1
なんという驚き:Edgeだけがこれをサポートしない:)
Xenos

31

できません。開始点をシミュレートするセレクターはありません。

jQueryがそれを行う方法(qsa好みの動作ではないため)elemは、IDがあるかどうかを確認し、IDがない場合は一時的にIDを追加してから、完全なセレクター文字列を作成します。

基本的には次のようにします:

var sel = '> someselector';
var hadId = true;
if( !elem.id ) {
    hadID = false;
    elem.id = 'some_unique_value';
}

sel = '#' + elem.id + sel;

var result = document.querySelectorAll( sel );

if( !hadId ) {
    elem.id = '';
}

これは確かにjQueryコードではありませんが、私が覚えている限りでは、基本的に彼らは何をしているのでしょう。この状況だけでなく、ネストされた要素のコンテキストからセレクターを実行している状況でも。

Sizzleのソースコード


1
執筆時点では正しいですが、更新されたメソッドについては@avetiskの回答を参照してください。
lazd 2014年

23

完全:スコープポリフィル

avetisk挙げセレクタAPI 2つの用途の:scope擬似セレクタ。
これを(をサポートするquerySelector)すべてのブラウザで機能させるには、ここにポリフィルがあります。

(function(doc, proto) {
  try { // check if browser supports :scope natively
    doc.querySelector(':scope body');
  } catch (err) { // polyfill native methods if it doesn't
    ['querySelector', 'querySelectorAll'].forEach(function(method) {
      var nativ = proto[method];
      proto[method] = function(selectors) {
        if (/(^|,)\s*:scope/.test(selectors)) { // only if selectors contains :scope
          var id = this.id; // remember current element id
          this.id = 'ID_' + Date.now(); // assign new unique id
          selectors = selectors.replace(/((^|,)\s*):scope/g, '$1#' + this.id); // replace :scope with #ID
          var result = doc[method](selectors);
          this.id = id; // restore previous id
          return result;
        } else {
          return nativ.call(this, selectors); // use native code for other selectors
        }
      }
    });
  }
})(window.document, Element.prototype);

使用法

node.querySelector(':scope > someselector');
node.querySelectorAll(':scope > someselector');

歴史的な理由から、私の以前の解決策

すべての回答に基づく

// Caution! Prototype extending
Node.prototype.find = function(selector) {
    if (/(^\s*|,\s*)>/.test(selector)) {
        if (!this.id) {
            this.id = 'ID_' + new Date().getTime();
            var removeId = true;
        }
        selector = selector.replace(/(^\s*|,\s*)>/g, '$1#' + this.id + ' >');
        var result = document.querySelectorAll(selector);
        if (removeId) {
            this.id = null;
        }
        return result;
    } else {
        return this.querySelectorAll(selector);
    }
};

使用法

elem.find('> a');

Date.now()古いブラウザではサポートされておらず、置き換えることができますnew Date().getTime()
Christophe

4

調べている要素のタグ名がわかっている場合は、それをセレクターで使用して目的の機能を実現できます。

たとえば、<select>とを持つが<option>あり<optgroups><option>その直下の子であるs のみが必要で、内部のは必要ない場合<optgoups>

<select>
  <option>iPhone</option>
  <optgroup>
    <option>Nokia</option>
    <option>Blackberry</option>
  </optgroup>
</select>

したがって、select要素への参照があると、次のようにして(驚くべきことに)直接の子を取得できます。

selectElement.querySelectorAll('select > option')

Chrome、Safari、Firefoxで動作するようですが、IEではテストしていません。= /


8
警告:この回答は実際には範囲を制限するものではありません。パターンがより深いネストレベルで繰り返される場合、直接の子ではない場合でも、パターンが選択されます。 <ul id="start"> <li>A</li> <li> <ul> <li>b</li> <li>c</li> </ul> </li> </ul> var result = document.getElementById('start').querySelectorAll('ul>li'); -> 4つのli要素がすべて選択されます!
Risord 2016

1
<select>は同じ親に二つの要素があったことを禁じました。
トマーシュZato -復活モニカ

4

最終的に直接の子を検索したい場合(例:> div > spanではなく)、Element.matches()を試すことができます。

const elems = Array.from(elem.children).filter(e => e.matches('.my-class'))

2

請求

個人的に私はパトリックdwから答えを受け取り、彼の答えを+1しました。私の答えは代替の解決策を探すことです。私はそれが反対投票に値するとは思わない。

これが私の試みです:

function q(elem){
    var nodes = elem.querySelectorAll('someSeletor');
    console.log(nodes);
    for(var i = 0; i < nodes.length; i++){
        if(nodes[i].parentNode === elem) return nodes[i];
    }
}

http://jsfiddle.net/Lgaw5/8/を参照してください


1
それに関するいくつかの問題。@disfatedはで動作することを望んでいます。querySelectorつまり、それは:eq()使用できません。可能であっても、セレクターは、親のインデックス(では、を取得する場所):eq()ではなく、ページの外観に対応する要素を返します。:eq()idx
user113716 '26 / 06/26

:eq()とquerySelectorについて+1。そして、コンテキスト$(elem).parent()を追加する必要があります。
Liangliang Zheng

残念ながらそれもうまくいきません。セレクターが親のコンテキストから実行される場合、セレクターは左端の子から始まり、どの程度深くネストされていても、一致するすべての要素を見つけます。つまり、elemがインデックス4にあるが、前の兄弟には異なるtagNameがあるが、その内部にと一致する要素がネストされている場合tagName、そのネストされた要素は、ターゲットにしている要素の前に結果に含まれ、再びスローされますインデックス。ここでは一例です
user113716

とにかく、あなたが最終的にやっていることは、問題のコードのより複雑なバージョンであり、機能します。$('> someselector', elem);; o)
user113716 2011年

はい。ただし、その1つの増分をハードコードする必要がありました。それには事前の知識が必要です。同様の要素をもう1つ追加すると、再び壊れます。; o)jsfiddle.net/Lgaw5/3
user113716

1

それは私のために働きました:

Node.prototype.search = function(selector)
{
    if (selector.indexOf('@this') != -1)
    {
        if (!this.id)
            this.id = "ID" + new Date().getTime(); 
        while (selector.indexOf('@this') != -1)
            selector = selector.replace('@this', '#' + this.id);
        return document.querySelectorAll(selector);
    } else 
        return this.querySelectorAll(selector);
};

直接の子を検索する場合は、>の前に@thisキーワークを渡す必要があります。


現在受け入れられている答えと同じようです...ところで、奇妙な「@this」構文の意味は何ですか?なぜ正規表現で「>」をテストしないのですか?
2013

1

以下は、直接の子に対してのみCSSセレクタークエリを実行するための簡略化された一般的な方法です"foo[bar], baz.boo"

var count = 0;
function queryChildren(element, selector) {
  var id = element.id,
      guid = element.id = id || 'query_children_' + count++,
      attr = '#' + guid + ' > ',
      selector = attr + (selector + '').replace(',', ',' + attr, 'g');
  var result = element.parentNode.querySelectorAll(selector);
  if (!id) element.removeAttribute('id');
  return result;
}


*** Example Use ***

queryChildren(someElement, '.foo, .bar[xyz="123"]');

1

ありますクエリ相対のために非常に便利な代替品ですlibに、クエリ・セレクタは。子セレクター('> *'および:scopeIE8を含む)をポリフィルし、:rootセレクターを正規化します。また、それはのようないくつかの特別な相対pseudosを提供し:closest:parent:prev:next、念のため。


0

要素にIDがあるかどうかを確認し、そうでない場合はランダムIDを追加して、それに基づいて検索します

function(elem) {
      if(!elem.id)
          elem.id = Math.random().toString(36).substr(2, 10);
      return elem.querySelectorAll(elem.id + ' > someselector');
    };

同じことをします

$("> someselector",$(elem))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.