259 votes

Utilisation de querySelectorAll pour récupérer les enfants directs

Je suis en mesure de le faire :

<div id="myDiv">
   <div class="foo"></div>
</div>

myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");

C'est-à-dire que je peux récupérer avec succès tous les enfants directs de l'élément myDiv qui ont la classe .foo .

Le problème, c'est que cela m'ennuie de devoir inclure l'élément #myDiv dans le sélecteur, car j'exécute la requête sur le fichier myDiv (il est donc manifestement redondant).

Je devrais pouvoir quitter le #myDiv mais le sélecteur n'est alors pas une syntaxe légale puisqu'il commence par un > .

Quelqu'un sait-il comment écrire un sélecteur qui ne récupère que les enfants directs de l'élément sur lequel le sélecteur est exécuté ?

308voto

natevw Points 3543

Bonne question. À l'époque où elle a été posée, une méthode universellement mise en œuvre pour effectuer des "combinator rooted queries" (en tant que John Resig les a appelés ) n'existait pas.

Aujourd'hui, le :scope a été introduite. Elle n'est pas soutenu sur les versions [pré-Chrominum] d'Edge ou d'IE, mais il est pris en charge par Safari depuis quelques années déjà. En utilisant cela, votre code pourrait devenir :

let myDiv = getElementById("myDiv");
myDiv.querySelectorAll(":scope > .foo");

Notez que, dans certains cas, vous pouvez également ignorer l'option .querySelectorAll et utiliser d'autres bonnes vieilles fonctionnalités de l'API DOM. Par exemple, au lieu de myDiv.querySelectorAll(":scope > *") vous pouvez simplement écrire myDiv.children par exemple.

Sinon, si vous ne pouvez pas encore compter sur :scope Je ne vois pas d'autre moyen de gérer votre situation sans ajouter une logique de filtrage plus personnalisée (par exemple, trouver myDiv.getElementsByClassName("foo") dont .parentNode === myDiv ), et ce n'est évidemment pas l'idéal si vous essayez de soutenir un chemin de code qui veut juste prendre une chaîne de sélection arbitraire en entrée et une liste de correspondances en sortie ! Mais si comme moi vous avez fini par poser cette question simplement parce que vous étiez bloqué en pensant que "tout ce que vous aviez c'était un marteau", n'oubliez pas qu'il y a une variété de autres les outils offerts par le DOM.

156voto

lazd Points 591

Quelqu'un sait-il comment écrire un sélecteur qui ne récupère que les enfants directs de l'élément sur lequel le sélecteur est exécuté ?

La bonne façon d'écrire un sélecteur qui est "enraciné" dans l'élément courant est d'utiliser :scope .

var myDiv = getElementById("myDiv");
var fooEls = myDiv.querySelectorAll(":scope > .foo");

Cependant, la prise en charge des navigateurs est limitée et vous aurez besoin d'une cale si vous voulez l'utiliser. J'ai construit scopedQuerySelectorShim à cette fin.

10voto

Randy Hall Points 605

Si vous êtes sûr que l'élément est unique (comme c'est le cas avec l'ID) :

myDiv.parentElement.querySelectorAll("#myDiv > .foo");

Pour une solution plus "globale" : (utiliser un matchesSelector shim )

function getDirectChildren(elm, sel){
    var ret = [], i = 0, l = elm.childNodes.length;
    for (var i; i < l; ++i){
        if (elm.childNodes[i].matchesSelector(sel)){
            ret.push(elm.childNodes[i]);
        }
    }
    return ret;
}

elm est votre élément parent, et sel est votre sélecteur. Il pourrait tout à fait être utilisé comme prototype.

10voto

theMaxx Points 551

J'utilise ceci :

Vous pouvez éviter de taper deux fois "myDiv" ET utiliser la flèche.
Il y a bien sûr toujours d'autres possibilités.
Un navigateur moderne est probablement nécessaire.


<!-- Sample Code -->

<div id="myDiv">
    <div class="foo">foo 1</div>
    <div class="foo">foo 2
        <div class="bar">bar</div>
    </div>
    <div class="foo">foo 3</div>
</div>

// Return HTMLCollection (Matches 3 Elements)

var allMyChildren = document.querySelector("#myDiv").children;

// Return NodeList (Matches 7 Nodes)

var allMyChildren = document.querySelector("#myDiv").childNodes;

// Match All Children With Class Of Foo (Matches 3 Elements)

var myFooChildren = document.querySelector("#myDiv").querySelectorAll(".foo");

// Match Second Child With Class Of Foo (Matches 1 Element)

var mySecondChild = document.querySelector("#myDiv").querySelectorAll(".foo")[1];

// Match All Children With Class Of Bar (Matches 1 Element)

var myBarChild = document.querySelector("#myDiv").querySelector(".bar");

// Match All Elements In "myDiv" (Matches 4 Elements)

var myDescendants = document.querySelector("#myDiv").querySelectorAll("*");

7voto

csuwldcat Points 2299

Voici une méthode flexible, écrite en JS vanille, qui vous permet d'exécuter une requête de sélecteur CSS sur les seuls enfants directs d'un élément :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X