【问题标题】:CSS or JS to modify (replace) every word on webpageCSS 或 JS 修改(替换)网页上的每个单词
【发布时间】:2018-01-18 08:34:31
【问题描述】:

对于一个复活节彩蛋,我希望能够用一个常量字符串替换我网页上的每个单词。现有问题的重点是替换某些 词、不包含许多其他元素的元素,或使用 JQuery 等库。应保留结构,即<li>Some text <span>link</span> more text</li> 应变为<li>Lorem Lorem <span>Lorem</span> Lorem Lorem</li>

如果我这样遍历 DOM:

recur (el) {
  if (typeof el === 'undefined') {
    el = document.body
  }
  for (let e of el.childNodes) {
    if (e.nodeType === 1) {
      recur(e)
    } else if (e.nodeType === 3) {
      console.log(e)
    }
  }
}

我得到了很多#text 元素和看起来像字符串的东西。我怎样才能真正改变它们?我尝试分配给父数组中的相应元素,但这不起作用:

Uncaught TypeError: Failed to set an indexed property on 'NodeList': Index property setter is not supported.

修改此类文本节点的父节点的innerHTML属性是否更好?

或者您会推荐一种完全不同的方法吗?纯 CSS 的解决方案也很棒。

【问题讨论】:

  • 如果重复使用相同的替换字符串,您可以只计算元素中的单词数,然后将节点innerHTML 设置为许多新单词。
  • Change textNode value的可能重复
  • 克里斯:你的意思是innerHTML?是的,但相关的元素是什么?如果我有嵌套怎么办<li>Some text <span>link</span> more text</li>
  • 你能给我们提供一个示例输入和一个示例输出吗?
  • 我在问题的第一段中添加了一个。

标签: javascript html css


【解决方案1】:

多么有趣!您可以获取并分配给文本节点的nodeValue。正则表达式至少会让您与/[\w\x7f-\xff]+/g 非常接近(十六进制值与大部分特殊字符匹配。 See here)

(function recur (el) {
  if (typeof el === 'undefined') {
    el = document.body
  }
  for (let e of el.childNodes) {
    if (e.nodeType === Node.ELEMENT_NODE) {
      recur(e)
    } else if (e.nodeType === Node.TEXT_NODE) {
      e.nodeValue = e.nodeValue.replace(/[\w\x7f-\xff]+/g, 'lorem')
    }
  }
})();
<html>
<head>
<title>
A Simple HTML Document
</title>
</head>
<body>
<p>This is a very schön HTML document</p>
<p>It only has <b>two</b> paragraphs</p>
</body>
</html>

【讨论】:

  • 小建议:使用 Node.ELEMENT_NODE 和 Node.TEXT_NODE 常量可以更容易理解其工作原理。
  • 太棒了!该解决方案有效,我只需要稍微摆弄正则表达式以包含变音符号等。
  • @Semicolon 一个非常好的建议。对于那些想知道的人,分号指的是这些常量:developer.mozilla.org/en-US/docs/Web/API/Node/…
  • 或者,您可以使用类似const n = e.nodeValue.split(' ').filter(str =&gt; str.trim()).length; e.nodeValue = 'Lorem '.repeat(n)
【解决方案2】:

我强烈建议您考虑使用TreeWalker,这是一个用于此目的的 DOM API - 遍历 DOM 树。它可以找到文档中的所有文本节点并且非常有效地找到它们,因为现代浏览器在本机代码中运行这样的 API 调用。

第一个参数是您要开始搜索的节点,第二个参数是要查找的节点类型。在这种情况下,我们从document.body 开始并查找所有textNodes。然后,在while 循环中,您在节点上执行您想要的任何操作,然后继续执行下一个操作。

通过这种植入,您不必处理尴尬的内部标签或空白 - 所有文本都会为您很好地捆绑在一起。而且,它会比你在客户端 JS 中编写的树遍历更快。

const matchAllExceptWhitespace = /\w+/g;
const treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null, false);
const word = 'Lorem';

let node;

while (node = treeWalker.nextNode()) {
  node.textContent = node.textContent.replace(matchAllExceptWhitespace, word);
}
<h1>A paragraph</h1>
<p>This is a sentence.</p>
<ul>
    <li>Some text <span>link</span> more text</li>.
</ul>

【讨论】:

  • 不是更简单吗:let node; while (node = treeWalker.nextNode()) { node.textContent = node.textContent.replace(matchAllExceptWhitespace, word); }?
  • 是的,谢谢,这让事情变得更简单了,我已经更新了 sn-p。还有一个可以使用的currentNode() 的引用。
【解决方案3】:

这是最简单的方法之一(借用this answer的一些帮助):

function ReplaceChildText(node, replaceText) {
    //Is this a text node?
    if (node.nodeType === 3) {
      //Simply replace the value with your regex:
      node.nodeValue = node.nodeValue.replace(/\w+/g, replaceText);
    } else {
        //Loop through all the children, to look for more text nodes
        for (let child of node.childNodes) {
            //Yay, recursion
            ReplaceChildText(child, replaceText);
        }
    }
}

ReplaceChildText(document.body, 'Loreum');
&lt;div id="test"&gt;&lt;li&gt;Some text &lt;b&gt;link&lt;/b&gt; more text&lt;/li&gt;&lt;/div&gt;

【讨论】:

  • 可能会遇到其他没有 childNodes 的节点类型,例如 Comment,因此检查它是否是 Element(或者它是否有 childNodes)很重要。
  • @Semicolon 刚刚加了注释节点,脚本依然执行完美(childNodes简单返回0长度)
  • 哦,很高兴知道。我没有意识到 childNodes 是从 Node 继承的。
猜你喜欢
  • 1970-01-01
  • 2014-04-24
  • 1970-01-01
  • 2016-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
相关资源
最近更新 更多