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é ?

3voto

Melle Points 2157

La solution suivante est différente de celles proposées jusqu'à présent et fonctionne pour moi.

L'idée est de sélectionner d'abord tous les enfants correspondants, puis de filtrer ceux qui ne sont pas des enfants directs. Un enfant est un enfant direct s'il n'a pas de parent correspondant avec le même sélecteur.

function queryDirectChildren(parent, selector) {
    const nodes = parent.querySelectorAll(selector);
    const filteredNodes = [].slice.call(nodes).filter(n => 
        n.parentNode.closest(selector) === parent.closest(selector)
    );
    return filteredNodes;
}

HTH !

2voto

Mark K Points 21
function siblings(el) {
    return el.closest('*:not(:scope)').querySelectorAll(':scope > *');
}

Code JS pur

el - est votre élément Nous avons ici une fonction qui fonctionne dans les étapes suivantes :

  1. prend n'importe quel parent direct, mais pas el qu'on lui passe (le plus proche peut prendre el, donc on s'assure que el ne sera pas le résultat)
  2. prendre tous les enfants directs

1voto

cpi Points 41

J'ai créé une fonction pour gérer cette situation et j'ai pensé la partager.

getDirectDecendent(elem, selector, all){
    const tempID = randomString(10) //use your randomString function here.
    elem.dataset.tempid = tempID;

    let returnObj;
    if(all)
        returnObj = elem.parentElement.querySelectorAll(`[data-tempid="${tempID}"] > ${selector}`);
    else
        returnObj = elem.parentElement.querySelector(`[data-tempid="${tempID}"] > ${selector}`);

    elem.dataset.tempid = '';
    return returnObj;
}

Essentiellement, ce que vous faites est de générer une chaîne aléatoire (la fonction randomString est un module npm importé, mais vous pouvez créer la vôtre) et d'utiliser cette chaîne aléatoire pour garantir que vous obtenez l'élément que vous attendez dans le sélecteur. Vous êtes ensuite libre d'utiliser la fonction > après cela.

La raison pour laquelle je n'utilise pas l'attribut id est qu'il peut déjà être utilisé et que je ne veux pas le remplacer.

1voto

Netsi1964 Points 165

Vous pouvez étendre Element pour y inclure une méthode getDirectDesc() comme ceci :

Element.prototype.getDirectDesc = function() {
    const descendants = Array.from(this.querySelectorAll('*'));
    const directDescendants = descendants.filter(ele => ele.parentElement === this)
    return directDescendants
}

const parent = document.querySelector('.parent')
const directDescendants = parent.getDirectDesc();

document.querySelector('h1').innerHTML = `Found ${directDescendants.length} direct descendants`

<ol class="parent">
    <li class="b">child 01</li>
    <li class="b">child 02</li>
    <li class="b">child 03 <ol>
            <li class="c">Not directDescendants 01</li>
            <li class="c">Not directDescendants 02</li>
        </ol>
    </li>
    <li class="b">child 04</li>
    <li class="b">child 05</li>
    </ol>
    <h1></h1>

0voto

Dustin Poissant Points 30

Nous pouvons facilement obtenir tous les enfants directs d'un élément à l'aide de la fonction childNodes et nous pouvons sélectionner les ancêtres d'une classe spécifique avec querySelectorAll Il n'est donc pas difficile d'imaginer que nous pourrions créer une nouvelle fonction qui obtiendrait les deux et les comparerait.

HTMLElement.prototype.queryDirectChildren = function(selector){
  var direct = [].slice.call(this.directNodes || []); // Cast to Array
  var queried = [].slice.call(this.querySelectorAll(selector) || []); // Cast to Array
  var both = [];
  // I choose to loop through the direct children because it is guaranteed to be smaller
  for(var i=0; i<direct.length; i++){
    if(queried.indexOf(direct[i])){
      both.push(direct[i]);
    }
  }
  return both;
}

Remarque : cette opération renvoie un tableau de nœuds, et non une liste de nœuds.

Utilisation

 document.getElementById("myDiv").queryDirectChildren(".foo");

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