Javascript textNodes的getElementsByTagName()等效项

Javascript textNodes的getElementsByTagName()等效项,javascript,dom,dhtml,textnode,Javascript,Dom,Dhtml,Textnode,有没有办法获取文档中所有textNode对象的集合 getElementsByTagName()对于元素非常有效,但是textNodes不是元素 更新:我意识到这可以通过遍历DOM来实现——正如下面许多人所建议的那样。我知道如何编写DOM walker函数来查看文档中的每个节点。我希望有一个浏览器原生的方式来做这件事。毕竟有点奇怪,我可以通过一个内置调用获得所有的s,但不是所有的textNodes。更新: 我概述了这6种方法在1000次运行中的基本性能测试getElementsByTagName

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

getElementsByTagName()
对于元素非常有效,但是
textNode
s不是元素


更新:我意识到这可以通过遍历DOM来实现——正如下面许多人所建议的那样。我知道如何编写DOM walker函数来查看文档中的每个节点。我希望有一个浏览器原生的方式来做这件事。毕竟有点奇怪,我可以通过一个内置调用获得所有的
s,但不是所有的
textNode
s。

更新

我概述了这6种方法在1000次运行中的基本性能测试
getElementsByTagName
是最快的,但它做的工作是半途而废的,因为它不选择所有元素,而只选择一种特定类型的标记(我认为
p
),并且盲目地假设它的第一个子元素是文本元素。它可能有点缺陷,但只是为了演示,并将其性能与
TreeWalker
进行比较。看看结果

  • 使用树行者
  • 自定义迭代遍历
  • 自定义递归遍历
  • Xpath查询
  • 查询选择器
  • getElementsByTagName
  • 让我们假设有一种方法允许您以本机方式获取所有
    Text
    节点。您仍然需要遍历每个生成的文本节点并调用
    node.nodeValue
    ,才能像处理任何DOM节点一样获得实际文本。因此,性能问题不是迭代文本节点,而是迭代所有非文本节点并检查其类型。我认为(基于结果),
    TreeWalker
    的执行速度与
    getElementsByTagName
    一样快,如果不是更快的话(即使getElementsByTagName是残疾人)

    递归树遍历

    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);
            }
        }
    }
    
    查询选择全部

    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);
            }
        }
    }
    
    此外,您可能会发现此讨论很有帮助-

    /* 可以返回某个父元素的所有子代文本节点的数组, 或者,您可以向它传递一些函数并执行某些操作(查找、替换或其他任何操作) 将文本放在适当的位置

    此示例返回正文中非空白文本节点的文本:

    var A= document.deepText(document.body, function(t){
        var tem= t.data;
        return /\S/.test(tem)? tem: undefined;
    });
    alert(A.join('\n'))
    
    */


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

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

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

    var el1=document.childNodes[0]
    函数get(节点,ob)
    {
    ob=ob |{};
    if(node.childElementCount)
    {
    ob[node.nodeName]={}
    ob[node.nodeName][“text”]=[];
    对于(var x=0;x
    这是最快的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;
    }
    
    用法:

    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;
    }
    

    这里有一个更为惯用且(希望)更容易理解的替代方案

    函数getText(节点){ //递归到每个子节点 if(node.hasChildNodes()){ node.childNodes.forEach(getText); } //获取每个非空文本节点的内容 else if(node.nodeType===node.TEXT\u node){ const text=node.textContent.trim(); 如果(文本){ console.log(text);//做点什么 } } }
    createTreeWalker
    被弃用后,您可以使用

    /**
    *获取元素下的所有文本节点
    *@param{!Element}el
    *@return{Array}
    */
    函数getTextNodes(el){
    常量迭代器=document.createNodeIterator(el,NodeFilter.SHOW_TEXT);
    常量textNodes=[];
    让currentTextNode;
    而((currentTextNode=iterator.nextNode()){
    push(currentTextNode);
    }
    返回文本节点;
    }
    
    我在不同的浏览器中获得了上述每种方法的混合结果-以上这些结果是针对Chrome的。Firefox和Safari的行为非常不同。不幸的是,我没有访问IE的权限,但你们可以自己在IE上测试一下,看看它是否有效。至于浏览器优化,我不担心为每个浏览器选择不同的方法,只要差异在几十毫秒甚至几百毫秒左右。这是一个非常有用的答案,但要注意,不同的方法返回的结果非常不同。如果它们是父节点的第一个子节点,那么它们中的许多只会获得文本节点。其中一些节点只能获取文本,而其他节点只需稍作修改即可返回实际的文本节点。迭代树遍历中存在可能影响其性能的错误。将
    node.nodeType=3
    更改为
    node.nodeType==3
    @theazureshadow-感谢您指出了突出的
    =
    错误。我已经解决了这个问题,xpath版本只是返回
    Text
    对象,而不是像其他版本一样返回其中包含的实际字符串
    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;
    }
    
    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;
    }