You're on the right track looping through nodes. Do it recursively, building up the text of the text nodes, and recursing into elements if they don't match an exclude
selector (which could be a group [".a, .b"
], if you want to exclude multiple classes or similar):
function getTextExcept(element, exclude) {
return worker(element);
function worker(node, text = "") {
if (node.nodeType === Node.TEXT_NODE) {
text += node.nodeValue;
} else if (node.nodeType === Node.ELEMENT_NODE) {
if (!node.matches(exclude)) {
for (const child of node.childNodes) {
text = worker(child, text);
}
}
}
return text;
}
}
console.log(getTextExcept(
document.querySelector(".container"),
".exclude-text"
));
<div class="container">
<div class="exclude-text">Exclude me</div>
<div class="another-class">Add this text</div>
And this text here
</div>
An alternative approach is to clone the entire structure, remove the elements you don't want the text of, and then use .textContent
on the result. For a really large structure, that might be problematic in terms of memory (but it would have to be really large).
function getTextExcept(element, exclude) {
const clone = element.cloneNode(true);
for (const child of clone.querySelectorAll(exclude)) {
child.remove();
}
return clone.textContent;
}
console.log(getTextExcept(
document.querySelector(".container"),
".exclude-text"
));
<div class="container">
<div class="exclude-text">Exclude me</div>
<div class="another-class">Add this text</div>
And this text here
</div>