Update :
Ich habe einige grundlegende Leistungstests für jede dieser 6 Methoden über 1000 Läufe skizziert. getElementsByTagName
ist das schnellste, aber es macht einen halbherzigen Job, da es nicht alle Elemente auswählt, sondern nur einen bestimmten Tag-Typ (glaube ich p
) und blind davon ausgeht, dass sein erstes Kind ein Textelement ist. Es mag wenig fehlerhaft sein, aber es dient zu Demonstrationszwecken und zum Vergleich seiner Leistung mit TreeWalker
. Führen Sie die Tests selbst auf jsfiddle durch , um die Ergebnisse zu sehen.
- Verwenden eines TreeWalker
- Benutzerdefinierte iterative Durchquerung
- Benutzerdefinierte rekursive Durchquerung
- Xpath-Abfrage
- querySelectorAll
- getElementsByTagName
Nehmen wir für einen Moment an, dass es eine Methode gibt, mit der Sie alle Text
Knoten nativ abrufen können. Sie müssten immer noch jeden resultierenden Textknoten durchlaufen und aufrufen node.nodeValue
, um den tatsächlichen Text zu erhalten, wie Sie es mit jedem DOM-Knoten tun würden. Das Problem der Leistung besteht also nicht darin, Textknoten zu durchlaufen, sondern alle Knoten, die kein Text sind, zu durchlaufen und ihren Typ zu überprüfen. Ich würde argumentieren (basierend auf den Ergebnissen), dass TreeWalker
die Leistung genauso schnell ist getElementsByTagName
, wenn nicht sogar schneller (selbst wenn getElementsByTagName behindert spielt).
Lief jeden Test 1000 Mal.
Methode Gesamt ms Durchschnitt ms
--------------------------------------------------
document.TreeWalker 301 0.301
Iterativer Traverser 769 0,769
Rekursiver Traverser 7352 7.352
XPath-Abfrage 1849 1.849
querySelectorAll 1725 1.725
getElementsByTagName 212 0.212
Quelle für jede Methode:
TreeWalker
function nativeTreeWalker() {
var walker = document.createTreeWalker(
document.body,
NodeFilter.SHOW_TEXT,
null,
false
);
var node;
var textNodes = [];
while(node = walker.nextNode()) {
textNodes.push(node.nodeValue);
}
}
Rekursive Baumdurchquerung
function customRecursiveTreeWalker() {
var result = [];
(function findTextNodes(current) {
for(var i = 0; i < current.childNodes.length; i++) {
var child = current.childNodes[i];
if(child.nodeType == 3) {
result.push(child.nodeValue);
}
else {
findTextNodes(child);
}
}
})(document.body);
}
Iterative Baumdurchquerung
function customIterativeTreeWalker() {
var result = [];
var root = document.body;
var node = root.childNodes[0];
while(node != null) {
if(node.nodeType == 3) {
result.push(node.nodeValue);
}
if(node.hasChildNodes()) {
node = node.firstChild;
}
else {
while(node.nextSibling == null && node != root) {
node = node.parentNode;
}
node = node.nextSibling;
}
}
}
querySelectorAll
function nativeSelector() {
var elements = document.querySelectorAll("body, body *");
var results = [];
var child;
for(var i = 0; i < elements.length; i++) {
child = elements[i].childNodes[0];
if(elements[i].hasChildNodes() && child.nodeType == 3) {
results.push(child.nodeValue);
}
}
}
getElementsByTagName (Handicap)
function getElementsByTagName() {
var elements = document.getElementsByTagName("p");
var results = [];
for(var i = 0; i < elements.length; i++) {
results.push(elements[i].childNodes[0].nodeValue);
}
}
XPath
function xpathSelector() {
var xpathResult = document.evaluate(
"//*/text()",
document,
null,
XPathResult.ORDERED_NODE_ITERATOR_TYPE,
null
);
var results = [], res;
while(res = xpathResult.iterateNext()) {
results.push(res.nodeValue);
}
}
Diese Diskussion ist möglicherweise auch hilfreich - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node
node.nodeType = 3
zunode.nodeType == 3
=
Fehler hingewiesen hast . Ich habe das behoben, und die xpath-Version gab einfachText
Objekte zurück und nicht die darin enthaltene tatsächliche Zeichenfolge wie die anderen Methoden. Die Methode, mit der nur der Text des ersten Kindes abgerufen wird, ist absichtlich falsch, und das habe ich am Anfang erwähnt. Ich werde die Tests erneut ausführen und die aktualisierten Ergebnisse hier veröffentlichen. Alle Tests (außer getElementsByTagName und xpath) geben die gleiche Anzahl von Textknoten zurück. XPath meldet ungefähr 20 Knoten mehr als die anderen, die ich vorerst ignorieren werde.Hier ist eine moderne
Iterator
Version der schnellsten TreeWalker-Methode:function getTextNodesIterator(el) { // Returns an iterable TreeWalker const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); walker[Symbol.iterator] = () => ({ next() { const value = walker.nextNode(); return {value, done: !value}; } }); return walker; }
Verwendung:
for (const textNode of getTextNodesIterator(document.body)) { console.log(textNode) }
Sicherere Version
Die direkte Verwendung des Iterators kann stecken bleiben, wenn Sie die Knoten während des Loopings verschieben. Dies ist sicherer, es wird ein Array zurückgegeben:
function getTextNodes(el) { // Returns an array of Text nodes const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT); const nodes = []; while (walker.nextNode()) { nodes.push(walker.currentNode); } return nodes; }
quelle
Ich weiß, dass Sie speziell nach einer Sammlung gefragt haben, aber wenn Sie das nur informell gemeint haben und es Ihnen egal war, ob sie alle zu einer großen Zeichenfolge zusammengefügt wurden, können Sie Folgendes verwenden:
var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
... wobei der erste Punkt der DOM3-Standardansatz ist. Beachten Sie jedoch, dass
innerText
Skript- oder Stil-Tag-Inhalte in Implementierungen, die dies unterstützen (mindestens IE und Chrome) , ausgeschlossen zu sein scheinen, währendtextContent
sie enthalten sind (in Firefox und Chrome).quelle
document.deepText= function(hoo, fun){ var A= [], tem; if(hoo){ hoo= hoo.firstChild; while(hoo!= null){ if(hoo.nodeType== 3){ if(typeof fun== 'function'){ tem= fun(hoo); if(tem!= undefined) A[A.length]= tem; } else A[A.length]= hoo; } else A= A.concat(document.deepText(hoo, fun)); hoo= hoo.nextSibling; } } return A; }
/ * Sie können ein Array aller untergeordneten Textknoten eines übergeordneten Elements zurückgeben oder eine Funktion übergeben und etwas (Suchen oder Ersetzen oder was auch immer) an dem vorhandenen Text ausführen.
In diesem Beispiel wird der Text der Nicht-Leerzeichen-Textknoten im Textkörper zurückgegeben:
var A= document.deepText(document.body, function(t){ var tem= t.data; return /\S/.test(tem)? tem: undefined; }); alert(A.join('\n'))
* /
Praktisch zum Suchen und Ersetzen, Hervorheben usw.
quelle
Hier ist eine Alternative, die etwas idiomatischer und (hoffentlich) leichter zu verstehen ist.
function getText(node) { // recurse into each child node if (node.hasChildNodes()) { node.childNodes.forEach(getText); } // get content of each non-empty text node else if (node.nodeType === Node.TEXT_NODE) { const text = node.textContent.trim(); if (text) { console.log(text); // do something } } }
quelle
var el1 = document.childNodes[0] function get(node,ob) { ob = ob || {}; if(node.childElementCount) { ob[node.nodeName] = {} ob[node.nodeName]["text"] = []; for(var x = 0; x < node.childNodes.length;x++) { if(node.childNodes[x].nodeType == 3) { var txt = node.childNodes[x].nodeValue; ob[node.nodeName]["text"].push(txt) continue } get(node.childNodes[x],ob[node.nodeName]) }; } else { ob[node.nodeName] = (node.childNodes[0] == undefined ? null :node.childNodes[0].nodeValue ) } return ob } var o = get(el1) console.log(o)
quelle
nachdem
createTreeWalker
veraltet ist, können Sie verwenden/** * Get all text nodes under an element * @param {!Element} el * @return {Array<!Node>} */ function getTextNodes(el) { const iterator = document.createNodeIterator(el, NodeFilter.SHOW_TEXT); const textNodes = []; let currentTextNode; while ((currentTextNode = iterator.nextNode())) { textNodes.push(currentTextNode); } return textNodes; }
quelle