更快地替换所有dom元素中的文本?

时间:2017-02-04 13:06:10

标签: javascript html html5 dom dom-traversal

我试图替换标签之间的所有文本,我想知道最快的方式。

一个例子是尝试用任意字符串helloWorld替换所有文本,以便:

<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>

成为这个:

<div>
    <div>
        helloWorld
        <div>
            helloWorld
        </div>
    </div>
</div>

我目前的方法是:

  • 对DOM进行深度优先搜索(DFS)
  • 对每个元素进行解析并确定哪个部分是文本,哪个部分是元素。
  • 对于文本替换它的部分。

这对我来说会非常慢,尤其是尝试为大型文档执行此操作并且必须多次重复此过程。有更快的方法吗?

5 个答案:

答案 0 :(得分:3)

您不需要解析每个元素来查找文本节点,您只需递归遍历元素的childNodes属性

&#13;
&#13;
var newText = 'hello world';
function replaceTextNodes(node) {
  node.childNodes.forEach(function(el) {
    if (el.nodeType === 3) {  // If this is a text node, replace the text
      if (el.nodeValue.trim() !== "") { // Ignore this node it it an empty text node
        el.nodeValue = newText;
      }
    } else { // Else recurse on this node
      replaceTextNodes(el);
    }
  });
}

var onClick = replaceTextNodes.bind(null, document.querySelector('#container'));
document.querySelector('#replace').addEventListener('click', onClick);
&#13;
<div id='container'>
  <div>
    RandomText1
    <div>
      RandomText2
      <ul>
        <li>RandomText3</li>
      </ul>
    </div>
  </div>
</div>
<button id="replace">Replace</button>
&#13;
&#13;
&#13;

答案 1 :(得分:2)

nodeIterator非常快。嵌套节点没有任何问题,无论它们埋藏多深。注意:添加了6级的红色文本。详情请参阅代码段。

<强>段

/* Create a custom filter which will...
||...the 3rd parameter of createNodeIterator method...
*/

function textFilter(node) {
  // if .nodeType is 3 (3 is text, 1 is element)
  if (node.nodeType === 3) {
    // Set .nodeValue to 'hellowWorld'
    node.nodeValue = 'helloWorld';
    // Return NodeFilter object to accept node
    return NodeFilter.FILTER_ACCEPT;
  }
  // Otherwise ignore node
  return NodeFilter.FILTER_SKIP;
}

function findText() {
  // Reference the rootNode
  var content = document.querySelector('body');

  /* Create nodeIterator passing
  || content or rootNode
  || NodeFilter object or WhatToShow property
  || Custom filter function
  */
  var iterator = document.createNodeIterator(content, NodeFilter.SHOW_TEXT, textFilter);
  // Advance to the next sibling or descend to node's children nodes 
  var node = iterator.nextNode();
  // While there is a node...
  while (node) {
    // ...Go on to it...rinse, lather, and repeat
    node = iterator.nextNode();
  }

}

findText();
.mark {
  color: red;
}
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    <div>
      <div>
        <div>
          <div class='mark'>
            6 Deep!
          </div>
        </div>
      </div>
    </div>
  </div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>
<div>
  <div>
    RandomText1
    <div>
      RandomText2
    </div>
  </div>
</div>

答案 2 :(得分:2)

使用TreeWalker对象作为DOM遍历的最快工具。
可以使用Document.createTreeWalker()方法创建 TreeWalker

function replaceAllText(newText) {
    var walker = document.createTreeWalker(
        document.body,  // root node
        NodeFilter.SHOW_TEXT,  // filtering only text nodes
        null,
        false
    );
    
    while (walker.nextNode()) {
        if (walker.currentNode.nodeValue.trim())  // if it's not empty(whitespaced) node
          walker.currentNode.nodeValue = newText;
    }
}

replaceAllText("helloWorld");
<div>
    <div>
        RandomText1
        <div>
            RandomText2
        </div>
    </div>
</div>

https://developer.mozilla.org/en-US/docs/Web/API/Document/createTreeWalker

Performance test demonstration

答案 3 :(得分:0)

浏览器完成的DOM搜索速度非常快,并且也进行了优化。 所以,我建议在DOM元素上添加一些需要更改的公共类,然后使用该类标识符对它们进行操作。

此外,

仅供参考,document.getElementById()适用于DFS并且非常有效。

答案 4 :(得分:0)

遍历HTML而不是像这样找到nodeValue:

document.querySelectorAll('div').forEach(function(o,i){
    console.log(o.firstChild && o.firstChild.nodeValue);
})

https://jsfiddle.net/q7ewbswx/