querySelector sucht nach unmittelbar untergeordneten Elementen [duplicate]

Lesezeit: 7 Minuten

Benutzer-Avatar
entfettet

Ich habe eine jquery-ähnliche Funktion:

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

Die Frage ist, wie kann ich das gleiche mit tun querySelector()?

Das Problem ist > Wahlschalter ein querySelector() erfordert, dass parent explizit angegeben wird. Gibt es eine Problemumgehung?

Benutzer-Avatar
avetisk

Obwohl es keine vollständige Antwort ist, sollten Sie die im Auge behalten W3C-Selektor-API v.2 die bereits in den meisten Browsern verfügbar ist, sowohl auf dem Desktop als auch auf Mobilgeräten, mit Ausnahme von IE (Edge scheint dies zu unterstützen): siehe vollständige Support-Liste.

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

  • Dies ist die richtige Antwort. Jedoch, Die Browserunterstützung ist eingeschränkt und Sie benötigen eine Unterlegscheibe, wenn Sie es verwenden möchten. ich baue scopedQuerySelectorShim für diesen Zweck.

    – faul

    15. Januar 2014 um 0:43 Uhr

  • Das :scope-Attribut wurde aus der aktuellen Spezifikation entfernt.

    – tobi

    18. Juli 2016 um 8:24 Uhr

  • Eigentlich, :scope ist noch bei angegeben drafts.csswg.org/selectors-4/#the-scope-pseudo. Bisher ist es nur die <style scoped> Attribut, das entfernt wurde; ob das auch dazu führen wird, ist unklar :scope entfernt (seit <style scoped> war ein wichtiger Anwendungsfall für :scope).

    – John Mellor

    26. August 2016 um 20:53 Uhr


  • Was für eine Überraschung: Nur Edge unterstützt dies nicht 🙂

    – Xenos

    30. Oktober 2019 um 18:15 Uhr

  • 2021 wird dies nun in allen modernen Browsern unterstützt.

    – Verärgerte Ziege

    23. Januar 2021 um 0:47 Uhr

Benutzer-Avatar
Benutzer113716

Du kannst nicht. Es gibt keinen Selektor, der Ihren Ausgangspunkt simuliert.

Die Art und Weise, wie jQuery es tut (mehr wegen einer Art und Weise, die qsa Verhaltensweisen, die ihnen nicht gefallen), besteht darin, dass sie prüfen, ob dies der Fall ist elem hat eine ID, und wenn nicht, fügen sie vorübergehend eine ID hinzu und erstellen dann eine vollständige Auswahlzeichenfolge.

Grundsätzlich würden Sie tun:

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 = '';
}

Dies ist sicherlich kein jQuery-Code, aber soweit ich mich erinnere, ist es im Grunde das, was sie tun. Nicht nur in dieser Situation, sondern in jeder Situation, in der Sie einen Selektor im Kontext eines verschachtelten Elements ausführen.

Quellcode für Sizzle

  • Korrekt zum Zeitpunkt des Schreibens, aber siehe Antwort von @avetisk für eine aktualisierte Methode.

    – faul

    15. Januar 2014 um 0:44 Uhr

Komplette :Scope Polyfill

Wie avetisk erwähnt hat, verwendet Selectors API 2 :scope Pseudoselektor.
Damit dies in allen Browsern funktioniert (die querySelector) hier ist die Füllwatte

(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);

Verwendungszweck

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

Aus historischen Gründen meine bisherige Lösung

Basierend auf allen Antworten

// 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);
    }
};

Verwendungszweck

elem.find('> a');

  • Date.now() wird von älteren Browsern nicht unterstützt und könnte durch ersetzt werden new Date().getTime()

    – Christoph

    14. September 2013 um 16:42 Uhr

Benutzer-Avatar
tuomassalo

Wenn Sie eventuell direkte Kinder finden möchten (und nicht z > div > span), Du kannst es versuchen Element.matches():

const elem = document.body
const elems = [...elem.children].filter(e => e.matches('b'))

console.log(elems)
<a>1</a>
<b>2</b>
<b>3</b>
<b>4</b>
<s>5</s>

Benutzer-Avatar
Liangliang Zheng

KLAGE

Persönlich würde ich die Antwort von Patrick dw nehmen, und +1 seine Antwort, meine Antwort ist für die Suche nach einer alternativen Lösung. Ich denke nicht, dass es eine Ablehnung verdient.

Hier mein Versuch:

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];
    }
}

sehen http://jsfiddle.net/Lgaw5/8/

  • Paar Probleme damit. @disfated möchte, dass es damit funktioniert querySelectorwas bedeutet, dass :eq() kann nicht verwendet werden. Selbst wenn dies möglich wäre, würde Ihr Selektor das Element zurückgeben, das ist :eq() zu seinem Erscheinen auf der Seite, nicht :eq() zum Index des übergeordneten Elements (dort erhalten Sie die idx).

    – Benutzer113716

    26. Juni 2011 um 2:36 Uhr


  • +1 über :eq() & querySelector. Und ich sollte den Kontext $(elem).parent() hinzufügen.

    – Liangliang Zheng

    26. Juni 2011 um 2:45 Uhr

  • Das wird leider auch nicht funktionieren. Wenn der Selektor im Kontext des übergeordneten Elements ausgeführt wird, beginnt es mit dem untergeordneten Element ganz links und findet alle übereinstimmenden Elemente, egal wie tief verschachtelt es ist. Also sagen die elem befindet sich an Index 4, aber es gibt ein früheres Geschwister, das eine andere hat tagNameaber es hat ein Element mit dem Matching darin verschachtelt tagNamewird dieses verschachtelte Element vor dem Element, auf das Sie abzielen, in die Ergebnisse aufgenommen, wodurch der Index erneut abgeworfen wird. Hier ist ein Beispiel

    – Benutzer113716

    26. Juni 2011 um 2:59 Uhr


  • … wie auch immer, was Sie letztendlich tun, ist eine komplexere Version des Codes in der Frage, die funktioniert. $('> someselector', elem); ;Ö)

    – Benutzer113716

    26. Juni 2011 um 3:01 Uhr


  • Ja, aber Sie mussten dieses einzelne Inkrement fest codieren. Dazu wären Vorkenntnisse erforderlich. Wenn ich ein weiteres ähnliches Element hinzufüge, ist es wieder kaputt. ;Ö) jsfiddle.net/Lgaw5/3

    – Benutzer113716

    26. Juni 2011 um 3:03 Uhr

Benutzer-Avatar
Vlad GURDIGA

Wenn Sie den Tag-Namen des gesuchten Elements kennen, können Sie ihn im Selektor verwenden, um das gewünschte Ergebnis zu erzielen.

Wenn Sie zum Beispiel eine <select> das hat <option>s und <optgroups>und du willst nur die <option>Das sind seine unmittelbaren Kinder, nicht die darin <optgoups>:

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

Wenn Sie also einen Verweis auf das select-Element haben, können Sie – überraschenderweise – seine unmittelbaren Kinder wie folgt erhalten:

selectElement.querySelectorAll('select > option')

Es scheint in Chrome, Safari und Firefox zu funktionieren, wurde aber nicht in IEs getestet. =/

  • Paar Probleme damit. @disfated möchte, dass es damit funktioniert querySelectorwas bedeutet, dass :eq() kann nicht verwendet werden. Selbst wenn dies möglich wäre, würde Ihr Selektor das Element zurückgeben, das ist :eq() zu seinem Erscheinen auf der Seite, nicht :eq() zum Index des übergeordneten Elements (dort erhalten Sie die idx).

    – Benutzer113716

    26. Juni 2011 um 2:36 Uhr


  • +1 über :eq() & querySelector. Und ich sollte den Kontext $(elem).parent() hinzufügen.

    – Liangliang Zheng

    26. Juni 2011 um 2:45 Uhr

  • Das wird leider auch nicht funktionieren. Wenn der Selektor im Kontext des übergeordneten Elements ausgeführt wird, beginnt es mit dem am weitesten links stehenden untergeordneten Element und findet alle übereinstimmenden Elemente, egal wie tief sie verschachtelt sind, und setzt sich fort. Also sagen die elem befindet sich an Index 4, aber es gibt ein früheres Geschwister, das eine andere hat tagNameaber es hat ein Element mit dem Matching darin verschachtelt tagNamewird dieses verschachtelte Element vor dem Element, auf das Sie abzielen, in die Ergebnisse aufgenommen, wodurch der Index erneut abgeworfen wird. Hier ist ein Beispiel

    – Benutzer113716

    26. Juni 2011 um 2:59 Uhr


  • … wie auch immer, was Sie letztendlich tun, ist eine komplexere Version des Codes in der Frage, die funktioniert. $('> someselector', elem); ;Ö)

    – Benutzer113716

    26. Juni 2011 um 3:01 Uhr


  • Ja, aber Sie mussten dieses einzelne Inkrement fest codieren. Dazu wären Vorkenntnisse erforderlich. Wenn ich ein weiteres ähnliches Element hinzufüge, ist es wieder kaputt. ;Ö) jsfiddle.net/Lgaw5/3

    – Benutzer113716

    26. Juni 2011 um 3:03 Uhr

Das Folgende ist eine vereinfachte, generische Methode zum Ausführen einer beliebigen CSS-Selektorabfrage nur über direkte untergeordnete Elemente – sie berücksichtigt auch kombinierte Abfragen, wie z "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"]');

1245020cookie-checkquerySelector sucht nach unmittelbar untergeordneten Elementen [duplicate]

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy