一尘不染

与textNodes等效的getElementsByTagName()

javascript

有什么方法可以获取textNode文档中所有对象的集合?

getElementsByTagName()对于Elements来说效果很好,但是textNodes不是Elements。

更新: 我意识到这可以通过遍历DOM来完成-如以下建议所示。我知道如何编写一个DOM-
walker函数来查看文档中的每个节点。我希望有某种浏览器本机的方法可以做到这一点。毕竟,我可以<input>通过一个内置调用获得所有s,但不是全部textNodes
有点奇怪。


阅读 398

收藏
2020-04-25

共1个答案

一尘不染

更新

我已经概述了这6种方法在1000次运行中的每种的一些基本性能测试。getElementsByTagName是最快的,但它完成了一半的工作,因为它不会选择所有元素,而是仅选择一种特定类型的标签(我认为p),并且盲目地假设其firstChild是文本元素。它可能没有什么瑕疵,但它只是出于演示目的,并将其性能与TreeWalker

  1. Using a TreeWalker
  2. Custom Iterative Traversal
  3. Custom Recursive Traversal
  4. Xpath query
  5. querySelectorAll
  6. getElementsByTagName

让我们暂时假设有一种方法可以让您Text本地获取所有节点。您仍然必须遍历每个结果文本节点并调用node.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

每种方法的来源:

树行者

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 (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);  /* Fixed a bug here. Thanks @theazureshadow */
    }
}
2020-04-25