Supposons une structure HTML comme indiqué:
const allElements = container.querySelectorAll('.MyClass'); const excludedElements = container.querySelectorAll('#excludedElement .MyClass'); var result = []; for (const element in allElements) { if (!excludedElements.Contains(element)) { result.Add(element); } }
Je veux tous les éléments à l'intérieur de la div "container" qui ont la classe "MyClass" à l'exception de ceux à l'intérieur de la div "exclusionElement". Dans ce cas, le résultat ne contient que les travées 4, 5 et 6.
Ma solution actuelle est d'abord d'obtenir tous les éléments avec "MyClass", puis d'obtenir tous les éléments à l'intérieur d'exclusElement avec "MyClass". Pour chaque élément de la première liste, nous vérifions s'il se trouve dans la seconde, et le sautons si c'est le cas. Il s'agit du temps d'exécution O (n ^ 2), donc j'aimerais éviter cela. Psuedocode pour référence:
<div id="container"> <div class="A"> <div id="excludedElement"> <p> <span class="MyClass">1</span> <span class="MyClass">2</span> <span class="MyClass">3</span> </p> </div> </div> <div class="B"> <p> <span class="MyClass">4</span> <span class="MyClass">5</span> <span class="MyClass">6</span> </p> </div> </div>
Y a-t-il un moyen de créer un sélecteur CSS dans querySelectorAll () qui peut récupérer cet ensemble particulier d'éléments?
Une façon est de supprimer temporairement excluElement de l'arborescence, recherchez "MyClass", puis remplacez le excluElement, mais je veux éviter de modifier le DOM.
4 Réponses :
Vous pouvez sélectionner tous les descendants de .MyClass
, puis .filter
la collection selon que l'élément en cours d'itération a un ancêtre #excludedElement
avec .closest
:
<div id="container"> <div class="A"> <div id="excludedElement"> <p> <span class="MyClass">1</span> <span class="MyClass">2</span> <span class="MyClass">3</span> </p> </div> </div> <div class="B"> <p> <span class="MyClass">4</span> <span class="MyClass">5</span> <span class="MyClass">6</span> </p> </div> </div>
const selector = ` :scope > .MyClass, :scope > *:not(#excludedElement) > .MyClass, :scope > *:not(#excludedElement) > *:not(#excludedElement) > .MyClass `; const classes = container.querySelectorAll(selector); for (const span of classes) { span.style.backgroundColor = 'yellow'; }
À moins que vous ne connaissiez à l'avance le type exact de structure des descendants de #container
, je ne pense pas qu'il y ait une manière élégante de faire cela avec une seule chaîne de requête; : not
n'accepte que des sélecteurs simples.
Juste à des fins d'information, une méthode idiote et répétitive que vous ne devriez pas utiliser serait d'utiliser la requête chaîne:
:scope > .MyClass, :scope > *:not(#excludedElement) > .MyClass, :scope > *:not(#excludedElement) > *:not(#excludedElement) > .MyClass ...
<div id="container"> <div class="A"> <div id="excludedElement"> <p> <span class="MyClass">1</span> <span class="MyClass">2</span> <span class="MyClass">3</span> </p> </div> </div> <div class="B"> <p> <span class="MyClass">4</span> <span class="MyClass">5</span> <span class="MyClass">6</span> </p> </div> </div>
const classes = [...container.querySelectorAll('.MyClass')] .filter(span => !span.closest('#excludedElement')); for (const span of classes) { span.style.backgroundColor = 'yellow'; }
Si la structure est prévisible et déjà connue:
container.querySelectorAll ('div: not (#excludedElement)> p .MyClass');
Si le la structure n'est pas connue et vous êtes d'accord pour ajouter des classes afin d'éviter O (n ^ 2):
const excludes = [...container.querySelectorAll('#excludedElement .MyClass')]; excludes.forEach(element => element.classList.add('excluded')); const filteredMyClass = [...container.querySelectorAll('.MyClass:not(.excluded)')];
@Mister Jojo travaille pour moi - try.jsoup.org/~bswchh1jSMyrvL0dVYrAMn1KQn4
L'OP utilise container.querySelectorAll
au lieu de document.querySelectorAll
Si vous utilisez document.querySelectorAll
cela fonctionne bien et peut probablement être simplifié en : non (#excludedElement)> p .MyClass
J'ai ceci ....
<div id="container"> <div class="A"> <div id="excludedElement"> <p> <span class="MyClass">1</span> <span class="MyClass">2</span> <span class="MyClass">3</span> </p> </div> </div> <div class="B"> <p> <span class="MyClass">4</span> <span class="MyClass">5</span> <span class="MyClass">6</span> </p> </div> </div>
const Excludes = [...container.querySelectorAll('#excludedElement .MyClass')] , noExcludes = [...container.querySelectorAll('.MyClass')].filter(el=>(!Excludes.includes(el))) ; noExcludes.forEach(element => element.style.backgroundColor = 'lightgreen');
Vous pouvez utiliser ce sélecteur précis dans .querySelectorAll()
:
<div id="container"> <div class="A"> <div id="excludedElement"> <p> <span class="MyClass">1</span> <span class="MyClass">2</span> <span class="MyClass">3</span> </p> </div> </div> <div class="B"> <p> <span class="MyClass">4</span> <span class="MyClass">5</span> <span class="MyClass">6</span> </p> </div> </div>
Exemple de travail:
const includedSpans = [... document.querySelectorAll(':not(#excludedElement) > p > .MyClass')]; includedSpans.forEach((includedSpan) => console.log(includedSpan.textContent));
:not(#excludedElement) > p > .MyClass