代码之家  ›  专栏  ›  技术社区  ›  levik

等同于textnodes的getElementsByTagName()

  •  67
  • levik  · 技术社区  · 16 年前

    有没有办法收集所有的 textNode 文档中的对象?

    getElementsByTagName() 对元素很有用,但是 文本节点 s不是元素。

    更新: 我意识到这可以通过遍历dom来实现——正如下面许多人所建议的那样。我知道如何编写一个dom walker函数来查看文档中的每个节点。我希望有一些浏览器本地的方式来做这件事。毕竟我能得到所有 <input> 有一个内置的调用,但不是全部 文本节点 S.

    6 回复  |  直到 7 年前
        1
  •  102
  •   Anurag    14 年前

    更新 :

    我已经概述了这6种方法在1000次运行中每种方法的一些基本性能测试。 getElementsByTagName 是最快的,但它做了一半的工作,因为它没有选择所有的元素,而是只有一种特定类型的标记(我认为 p )盲目地假设它的第一个子元素是文本元素。它可能有点缺陷,但它是为了演示和比较它的性能 TreeWalker . Run the tests yourselves on jsfiddle 看看结果。

    1. 使用树行者
    2. 自定义迭代遍历
    3. 自定义递归遍历
    4. XPath查询
    5. 查询选择器
    6. getElementsByTagname

    假设有一个方法可以让你 Text 本机节点。您仍然需要遍历每个结果文本节点并调用 node.nodeValue 获取实际的文本,就像处理任何dom节点一样。所以性能的问题不是遍历文本节点,而是遍历所有非文本节点并检查它们的类型。我认为(根据结果) 树人 表现和 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;
            }
        }
    }
    

    查询选择器

    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

        2
  •  4
  •   Brett Zamir    15 年前

    我知道你特别要求收藏,但如果你只是非正式地这么说,而不在乎它们是否都组合成一个大字符串,你可以使用:

    var allTextAsString = document.documentElement.textContent || document.documentElement.innerText;
    

    …第一项是dom3标准方法。但是请注意 innerText 在支持脚本或样式标记内容的实现(至少是ie和chrome)中,当 textContent 包括它们(在Firefox和Chrome中)。

        3
  •  2
  •   fregante    7 年前

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

    function getTextNodesIterator(el) { // Returns an iterable TreeWalker
        const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT);
        const next = () => {
            const value = walker.nextNode();
            return {
                value,
                done: !value
            };
        };
        walker[Symbol.iterator] = () => ({next});
        return walker;
    }
    

    用途:

    for (const textNode of getTextNodesIterator(document.body)) {
        console.log(textNode)
    }
    

    但是如果在循环过程中移动节点,循环可能会卡住。

    这样更安全:

    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;
    }
    
        4
  •  1
  •   kennebec    9 年前
     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'))
    

    */

    便于搜索和替换、突出显示等

        5
  •  0
  •   Mankament Gra    9 年前
    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)
    
        6
  •  0
  •   jtschoonhoven    7 年前

    这里有一个更好的选择,更习惯和(希望)更容易理解。

    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
            }
        }
    }
    
    推荐文章