Есть ли любой способ получить набор всех textNode
объекты в рамках документа?
getElementsByTagName()
работает отлично для Элементов, но textNode
s не являются Элементы.
Обновление: Я понимаю, что это может быть выполнено путем обхода DOM - как многие ниже предполагают. Я знаю, как записать функцию DOM-walker, которая смотрит на каждый узел в документе. Я надеялся, что был некоторый собственный браузером способ сделать это. В конце концов, немного странно, что я могу добраться весь <input>
s с единственным встроенным вызовом, но не всеми textNode
s.
Обновление :
Я обрисовал в общих чертах некоторые базовые тесты производительности для каждого из этих 6 методов за 1000 запусков. getElementsByTagName
- самый быстрый, но он выполняет половинчатую работу, так как он выбирает не все элементы, а только один конкретный тип тега (я думаю, p
) и слепо предполагает, что его firstChild - это текстовый элемент. Возможно, он немного ошибочен, но он предназначен для демонстрации и сравнения его производительности с TreeWalker
. Запустите тесты на jsfiddle , чтобы увидеть результаты.
Предположим на мгновение, что существует метод, позволяющий получить все Текстовые
узлы изначально. Вам все равно придется пройти по каждому результирующему текстовому узлу и вызвать узел .nodeValue
, чтобы получить фактический текст, как если бы вы делали это с любым узлом DOM. Таким образом, проблема производительности заключается не в переборе текстовых узлов, а в переборе всех узлов, не являющихся текстовыми, и проверке их типа. Я бы сказал (основываясь на результатах), что TreeWalker
работает так же быстро, как getElementsByTagName
, если не быстрее (даже с затрудненной игрой getElementsByTagName).
Ran each test 1000 times. Method Total ms Average ms -------------------------------------------------- document.TreeWalker 301 0.301 Iterative Traverser 769 0.769 Recursive Traverser 7352 7.352 XPath query 1849 1.849 querySelectorAll 1725 1.725 getElementsByTagName 212 0.212
Источник для каждого метода:
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);
}
}
Рекурсивный обход дерева
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);
}
Итерационный обход дерева
function customIterativeTreeWalker() {
var result = [];
var root = document.body;
var node = root.childNodes[0];
while(node != null) {
if(node.nodeType == 3) { /* Fixed a bug here. Thanks @theazureshadow */
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 *"); /* Fixed a bug here. Thanks @theazureshadow */
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 (гандикап)
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); /* Fixed a bug here. Thanks @theazureshadow */
}
}
Также вы можете найти это обсуждение полезно - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node
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;
}
/* Вы можете вернуть массив всех потомков текстовых узлов некоторого родительского элемента, или вы можете передать ему некоторую функцию и сделать что-то (найти или заменить или что-то еще) с текстом на месте.
Этот пример возвращает текст не пробельных текстовых узлов в теле:
var A= document.deepText(document.body, function(t){
var tem= t.data;
return /\S/.test(tem)? tem: undefined;
});
alert(A.join('\n'))
*/
Удобно для поиска и замены, выделения и т.д.