getElementsByTagName()等效于textNodes

lev*_*vik 73 javascript dom dhtml textnode

有没有办法获取textNode文档中所有对象的集合?

getElementsByTagName()适用于Elements,但textNode不是元素.

更新:我意识到这可以通过走DOM来实现 - 正如下面的许多建议.我知道如何编写一个DOM-walker函数来查看文档中的每个节点.我希望有一些浏览器原生的方式来做到这一点.毕竟有点奇怪的是,我可以<input>通过一个内置呼叫获得所有s,但不是全部textNode.

Anu*_*rag 109

更新:

我已经概述了超过1000次运行的这6种方法中的每种方法的一些基本性能测试.getElementsByTagName是最快的,但它做了一半的工作,因为它没有选择所有元素,而只选择一种特定类型的标签(我认为p),并盲目地假设它的firstChild是一个文本元素.它可能没有什么缺陷,但它的用于演示目的并将其性能与其进行比较TreeWalker.在jsfiddle上运行测试以查看结果.

  1. 使用TreeWalker
  2. 自定义迭代遍历
  3. 自定义递归遍历
  4. Xpath查询
  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

每种方法的来源:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

递归树遍历

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);
}
Run Code Online (Sandbox Code Playgroud)

迭代树遍历

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

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 */
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,您可能会发现此讨论很有帮助 - http://bytes.com/topic/javascript/answers/153239-how-do-i-get-elements-text-node

  • 我已经使测试等效并制作了一个jsPerf:http://jsperf.com/text-node-traversal (6认同)

fre*_*nte 6

这是Iterator最快的 TreeWalker 方法的现代版本:

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;
}
Run Code Online (Sandbox Code Playgroud)

用法:

for (const textNode of getTextNodesIterator(document.body)) {
    console.log(textNode)
}
Run Code Online (Sandbox Code Playgroud)

更安全的版本

如果在循环时移动节点,直接使用迭代器可能会卡住。这样更安全,它返回一个数组:

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;
}
Run Code Online (Sandbox Code Playgroud)


Bre*_*mir 5

我知道您特别要求一个集合,但如果您只是非正式地表达这一点并且不关心它们是否全部连接在一起形成一个大字符串,您可以使用:

var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
Run Code Online (Sandbox Code Playgroud)

...第一项是 DOM3 标准方法。但请注意,innerText在支持它的实现中(至少 IE 和 Chrome)似乎排除了脚本或样式标记内容,而textContent包含它们(在 Firefox 和 Chrome 中)。