Reputation:
My goal is to select h2, h3, h4
heading level elements in DOM except the ones that are inside docs-body__heading
class
I tried this:
document.querySelectorAll(`:not(.docs-body__heading) h2, h2, h4`);
Doesn't work.
So, how do I use querySelectorAll()
on DOM excluding some part of it?
Upvotes: 1
Views: 1792
Reputation: 1629
This one line will give you all you need!
document.querySelectorAll("*:not(.docs-body__heading) > h1, *:not(.docs-body__heading) > h2, *:not(.docs-body__heading) > h4");
Easier to read:
let not = "*:not(.docs-body__heading)";
document.querySelectorAll(`${not} > h1, ${not} > h2, ${not} > h4`);
Sample in use:
window.addEventListener('load', () => {
var elems = document.querySelectorAll("*:not(.docs-body__heading) > h1, *:not(.docs-body__heading) > h2, *:not(.docs-body__heading) > h4");
for(var i = 0 ; i < elems.length ; i++) {
elems[i].style.backgroundColor = "red";
}
});
<html>
<head>Selector</head>
<body>
<h1>1</h1>
<h2>2</h2>
<h4>3</h4>
<div class="docs-body__heading">
<h1>1</h1>
<h2>2</h2>
<h4>3</h4>
</div>
</body>
</html>
Upvotes: 0
Reputation: 136986
The easiest is by first getting all the elements then filtering out the ones that you don't want:
const elems = [...document.querySelectorAll('h2,h4')]
.filter( (elem) => !elem.matches('.docs-body__heading *') );
console.log(elems);
<div class="docs-body__heading">
<h2>do not select me</h2>
<div><h4>me neither</h4></div>
</div>
<div>
<h2>select me</h2>
<div><h4>and me</h4></div>
</div>
The fastest (in terms of performances) might be using a TreeWalker:
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_ELEMENT, {
acceptNode(elem) {
return elem.matches('.docs-body__heading') ?
NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;
}
}, true);
const elems = [];
while (walker.nextNode()) {
const tagname = walker.currentNode.tagName;
if (tagname === 'H2' || tagname === 'H4') {
elems.push(walker.currentNode);
}
}
console.log(elems);
<div class="docs-body__heading">
<h2>do not select me</h2>
<div>
<h4>me neither</h4>
</div>
</div>
<div>
<h2>select me</h2>
<div>
<h4>and me</h4>
</div>
</div>
But if you are not doing it in a kilometer long document with millions of DOM nodes, the first version should be largely enough.
Upvotes: 2
Reputation: 2089
I think it can be done only if the h2/h4 are direct childs of docs-body__heading
const x = document.querySelectorAll(":not(.docs-body__heading) > h2,h4");
console.log(x);
<div class="docs-body__heading">
<h2>A</h2>
</div>
<h4>B</h1>
<h2>C</h1>
Upvotes: 0
Reputation: 1862
Now you are excluding elements that have the docs-body__heading
class, to exclude element that are in it use:
document.querySelectorAll(`:not(.docs-body__heading > *) h2, h2, h4`);
Upvotes: 0