Je suis capable de faire ceci:
<div id="myDiv">
<div class="foo"></div>
</div>
myDiv = getElementById("myDiv");
myDiv.querySelectorAll("#myDiv > .foo");
Autrement dit, je peux récupérer avec succès tous les enfants directs de l' myDiv
élément qui ont la classe .foo
.
Le problème, c'est que cela me dérange de devoir inclure le #myDiv
dans le sélecteur, car j'exécute la requête sur l' myDiv
élément (donc c'est évidemment redondant).
Je devrais pouvoir laisser le #myDiv
désactivé, mais le sélecteur n'est pas une syntaxe légale puisqu'il commence par un >
.
Quelqu'un sait-il comment écrire un sélecteur qui n'obtient que les enfants directs de l'élément sur lequel le sélecteur s'exécute?
javascript
dom
css-selectors
mattsh
la source
la source
Réponses:
Bonne question. Au moment où cela a été demandé, il n'existait pas de moyen universellement implémenté de faire des «requêtes enracinées par combinateur» (comme les appelait John Resig ).
Maintenant, la pseudo-classe : scope a été introduite. Il n'est pas pris en charge sur les versions [pré-Chrominum] d'Edge ou d'IE, mais est déjà pris en charge par Safari depuis quelques années. En utilisant cela, votre code pourrait devenir:
Notez que dans certains cas, vous pouvez également ignorer
.querySelectorAll
et utiliser d'autres bonnes fonctionnalités de l'API DOM à l'ancienne. Par exemple, au lieu demyDiv.querySelectorAll(":scope > *")
vous pourriez simplement écriremyDiv.children
, par exemple.Sinon, si vous ne pouvez pas encore vous fier
:scope
, je ne peux pas penser à une autre façon de gérer votre situation sans ajouter plus de logique de filtre personnalisé (par exemple, trouver àmyDiv.getElementsByClassName("foo")
qui.parentNode === myDiv
), et évidemment pas idéal si vous essayez de prendre en charge un chemin de code qui vraiment 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 êtes resté coincé en pensant que "tout ce que vous aviez était un marteau", n'oubliez pas qu'il existe une variété d' autres outils que le DOM propose également.la source
myDiv.getElementsByClassName("foo")
n'est pas la même chose quemyDiv.querySelectorAll("> .foo")
, c'est plus commemyDiv.querySelectorAll(".foo")
(ce qui fonctionne en fait) en ce sens qu'il trouve tous les descendants.foo
par opposition à seulement les enfants.<style scoped>
) n'ont rien à voir avec le:scope
pseudo-sélecteur décrit dans cette réponse.La manière correcte d'écrire un sélecteur qui est "enraciné" sur l'élément courant est d'utiliser
:scope
.Cependant, la prise en charge du navigateur est limitée et vous aurez besoin d'un shim si vous souhaitez l'utiliser. J'ai construit scopedQuerySelectorShim à cet effet.
la source
:scope
spécification est actuellement un «projet de travail» et donc sujette à changement. Il est probable que cela fonctionnera toujours comme ça si / quand il sera adopté, mais un peu tôt pour dire que c'est la "bonne façon" de le faire à mon avis.Voici une méthode flexible, écrite en vanilla JS, qui vous permet d'exécuter une requête de sélection CSS uniquement sur les enfants directs d'un élément:
la source
Math.random().toString(36).substr(2, 10)
produire le même jeton plus d'une fois.any dupe would need to also be a child of the same parent node
, lesid
attributs concernent l’ensemble du document. Vous avez raison, les chances sont encore assez négligeables, mais merci d'avoir pris la haute route et d'ajouter ce compteur :)si vous savez avec certitude que l'élément est unique (comme votre cas avec l'ID):
Pour une solution plus "globale": (utilisez un shim matchesSelector )
où
elm
est votre élément parent etsel
est votre sélecteur. Pourrait totalement également être utilisé comme prototype.la source
matchesSelector
préfixe (qui ne fonctionne même pas dans la dernière version de Chrome), elle pollue l'espace de noms global (ret n'a pas été déclaré), elle ne retourne pas une NodeList comme on attend de querySelectorMethods. Je ne pense pas que ce soit une bonne solution, d'où le vote négatif.La solution suivante est différente de celles proposées jusqu'à présent et fonctionne pour moi.
La raison est que vous sélectionnez d'abord tous les enfants correspondants, puis que vous filtrez 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.
HTH!
la source
J'ai créé une fonction pour gérer cette situation, j'ai pensé la partager.
En substance, ce que vous faites est de générer une chaîne aléatoire (la fonction randomString ici est un module npm importé, mais vous pouvez créer le vôtre.) Puis d'utiliser cette chaîne aléatoire pour garantir que vous obtenez l'élément que vous attendez dans le sélecteur. Ensuite, vous êtes libre d'utiliser
>
après cela.La raison pour laquelle je n'utilise pas l'attribut id est que l'attribut id est peut-être déjà utilisé et je ne veux pas le remplacer.
la source
Eh bien, nous pouvons facilement obtenir tous les enfants directs d'un élément en utilisant
childNodes
et nous pouvons sélectionner des ancêtres avec une classe spécifique avecquerySelectorAll
, il n'est donc pas difficile d'imaginer que nous pourrions créer une nouvelle fonction qui obtient les deux et compare les deux.Remarque: Cela renverra un tableau de nœuds, pas une liste de nœuds.
Usage
la source
Je voudrais ajouter que vous pouvez étendre la compatibilité de : scope en attribuant simplement un attribut temporaire au nœud actuel.
la source
Je serais allé avec
la source
Je fais juste cela sans même essayer. Cela fonctionnerait-il?
Essayez-le, peut-être que cela fonctionne peut-être pas. Apolovies, mais je ne suis pas sur un ordinateur maintenant pour l'essayer (réponse depuis mon iPhone).
la source