web-dev-qa-db-fra.com

querySelector recherche des enfants immédiats

J'ai une fonction semblable à jquery:

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

La question est de savoir comment puis-je faire de même avec querySelector()?

Le problème est que le sélecteur > Dans querySelector() nécessite que le parent soit explicitement spécifié. Existe-t-il une solution de contournement?

81
disfated

Complet: portée polyfill

Comme avetisk a mentionné Sélecteurs API 2 utilise :scope pseudo-sélecteur.
Pour que cela fonctionne dans tous les navigateurs (qui supportent querySelector) voici le polyfill

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

Usage

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

Pour des raisons historiques, ma solution précédente

Basé sur toutes les réponses

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

Utilisation

elem.find('> a');
18
disfated

Bien que ce ne soit pas une réponse complète, vous devez garder un œil sur W3C Selector API v.2 qui est déjà disponible dans Google Chrome et Safari 7.x (les deux ordinateur de bureau et mobile), mais pour autant que je l'ai testé, toujours pas là dans Firefox et IE.

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

Tu ne peux pas. Il n'y a pas de sélecteur qui simule votre point de départ.

La façon dont jQuery le fait (plus à cause d'un comportement de qsa qui n'est pas à leur goût), c'est qu'ils vérifient si elem a un ID, et sinon, ils temporairement ajoutez un ID, puis créez une chaîne de sélection complète.

Fondamentalement, vous feriez:

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

Ce n'est certainement pas du code jQuery, mais d'après ce que je me souviens, c'est essentiellement ce qu'ils font. Pas seulement dans cette situation, mais dans toute situation où vous exécutez un sélecteur à partir du contexte d'un élément imbriqué.

Code source pour Sizzle

31
user113716

Si vous connaissez le nom de balise de l'élément que vous recherchez, vous pouvez l'utiliser dans le sélecteur pour obtenir ce que vous voulez.

Par exemple, si vous avez un <select> qui a <option>le sable <optgroups>, et vous ne voulez que le <option>s qui sont ses enfants immédiats, pas ceux à l'intérieur <optgoups>:

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

Donc, ayant une référence à l'élément select, vous pouvez - de manière surprenante - obtenir ses enfants immédiats comme ceci:

selectElement.querySelectorAll('select > option')

Il semble fonctionner dans Chrome, Safari et Firefox, mais n'a pas été testé dans les IE. = /

4
Vlad GURDIGA

Si vous souhaitez éventuellement trouver des enfants directs (et non par exemple > div > span), vous pouvez essayer Element.matches () :

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

Cela a fonctionné pour moi:

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

vous devrez passer le mot-clé @this avant le> lorsque vous souhaitez rechercher des enfants immédiats.

1
Davi

Ce qui suit est une méthode générique simplifiée pour exécuter n'importe quelle requête de sélecteur CSS sur uniquement des enfants directs - elle prend également en compte les requêtes combinées, comme "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
csuwldcat

Il y a relative à la requête lib, qui est un remplacement très pratique pour le sélecteur de requête . Il remplit le sélecteur d'enfants '> *' et :scope (y compris IE8), ainsi que normalise :root sélecteur. Il fournit également des pseudos relatifs spéciaux comme :closest, :parent, :prev, :next, Au cas où.

1
dy_

[~ # ~] revendication [~ # ~]

Personnellement, je prendrais la réponse de patrick dw, et +1 sa réponse, ma réponse est pour la recherche d'une solution alternative. Je ne pense pas que cela mérite un downvote.

Voici ma tentative:

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

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

1
Liangliang Zheng

vérifier si l'élément a un identifiant, ajouter un identifiant aléatoire et effectuer une recherche en fonction de celui-ci

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

fera la même chose que

$("> someselector",$(elem))
0
Zeeshan Anjum