3

I want to make a google chrome extension that replaces many different strings of text on a webpage to exhibit different words on client side. I came accros with this example below.

But I failed after trying a lot to change it to handle different words to replace. I can only handle one at a time.

i.e: I want to change all 'pink' words to 'blue', all 'cat' words to 'dog' and all 'boy' words to 'girl'. All at once.

How could I accomplish that? When I tinkered with this sample code all the times I would end only changing one of the words. In some cases, only on its first occurence.

Thanks in advance. I could not an answer to this question anywhere. Sorry if it looks noobish.

var elements = document.getElementsByTagName('*');

for (var i = 0; i < elements.length; i++) {
    var element = elements[i];

    for (var j = 0; j < element.childNodes.length; j++) {
        var node = element.childNodes[j];

        if (node.nodeType === 3) {
            var text = node.nodeValue;
            var replacedText = text.replace(/pink/gi, 'blue');

            if (replacedText !== text) {
                element.replaceChild(document.createTextNode(replacedText), node);
            }
        }
    }
}

4

4 回答 4

2

为了简化多个字符串到它们的替换的映射,您可以为替换创建一个 js 对象和相应的函数。

编辑以提高来自@MihaiIorga的每条评论的可用性(现在您只需编辑matches即可添加新的替换词)。例如(<div>为简单起见,仅在下面的代码段中选择标签,但您可以修改以选择所有元素、某些标签等):

const matches = { pink: 'blue', cat: 'dog', boy: 'girl' };
const replaces = Object.keys(matches).join('|');
const replacer = (s) => matches[s];
const elems = document.getElementsByTagName('div');
for (const elem of elems) {
  const s = elem.textContent;
  elem.textContent = s.replace(new RegExp(replaces, 'gi'), replacer);
}
<div>pink horse</div>
<div>green cat</div>
<div>purple boy moon</div>
<div>boy pink cat</div>

于 2019-01-07T20:42:37.237 回答
1

这里有几个关键点需要注意:

  1. 您已经通过通配符getElementsByTagName搜索获取了页面上的每个元素。因此,您不必将树向下遍历到子节点,因为您已经在初始搜索中捕获了它们,并且它们将在稍后的迭代中出现。

  2. 您不必替换字符串,将其与原始内容进行比较,然后替换节点。您可以直接替换任何节点的内部文本。

  3. 正则表达式中的方括号表示要匹配的字符的“类”。这意味着,如果没有特殊字符,它将匹配括号内的任何字符,而不是所有字符,并且顺序无关紧要。换句话说,/[one]/将匹配 o、n 或 e,它不会匹配字符串“one”。所以不需要方括号。

因此(不添加带有回调的方法——尽管您至少应该研究一下Array.forEach,因为它很有用!),您的代码简化为:

elements = document.getElementsByTagName("*");
for (var i = 0; i < elements.length; i++) {
    elements[i].innerText = elements[i].innerText.replace(/pink/gi, "blue");
}
于 2019-01-07T20:38:53.333 回答
1

通配符“太狂野”我认为您需要使用 '*:not(script):not(link) ... '

或者可能是这样的:var elements = document.getElementsByTagName('body')[0].querySelectorAll('*');

var elements = document.getElementsByTagName('body')[0].querySelectorAll('*:not(script)');
[].forEach.call(elements,function(elem){
    elem.textContent = elem.textContent ?  elem.textContent.replace(/pink/igm,'blue') : elem.innerText;
});
于 2019-01-07T20:22:53.697 回答
0

所以这里贴出了一个非常相似的问题,虽然它完全替换了每个子节点的文本内容,而不是选择性地替换。我已经对其进行了修改,这是一种简化它的可能方法。首先,使用一个函数,这样你就隐藏了一些复杂性。;)

let doc = document.querySelector("article"),
    pinkBtn = document.querySelector("#pink-btn"),
    pinkBoyBtn=document.querySelector("#pink-boy-btn"),
    pinkBoyDogBtn=document.querySelector("#pink-boy-dog-btn");


pinkBtn.addEventListener("click", function(){
  replaceTextNodes(doc, /pink/gi, "blue");
});
pinkBoyBtn.addEventListener("click", function(){
  replaceTextNodes(doc, /pink/gi, "blue");
  replaceTextNodes(doc, /boy/gi, "girl");
})
pinkBoyDogBtn.addEventListener("click", function(){
  replaceTextNodes(doc, /pink/gi, "blue");
  replaceTextNodes(doc, /boy/gi, "girl");
  replaceTextNodes(doc, /dog/gi, "cat");
})

function replaceTextNodes(node, oldText, newText) {
  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 = el.nodeValue.replace(oldText, newText);
      }
    } else { // Else recurse on this node
      replaceTextNodes(el, oldText, newText);
    }
  });
}
article {
 border: 1px solid blue;
 padding: 2px;
}
section{
 border: 1px dotted red;
 padding: 2px;
}
<article>
      <h1>This is a pink page</h1>

      <section id="home">
        Pink pink dog cat cow chicken boy
      </section>
      <section id="about">
        this is a story about a pink dog named Clyde.
      </section>
      <section id="projects">
        And more on the Clyde story. He has a boy.
      </section>
    </article>
    
    <button id="pink-btn">'pink'-&gt;'blue'</button> | <button id="pink-boy-btn">'pink'-&gt;'blue', 'boy'-&gt;'girl'</button> | <button id="pink-boy-dog-btn">'pink'-&gt;'blue', 'boy'-&gt;'girl', 'dog'-&gt;'cat'</button>

需要注意的是,我告诉它使用什么作为根节点,并更改其下方元素的所有文本。我将 DOM 节点、旧文本和新文本值作为参数传递。对于旧文本,我使用正则表达式。

棘手,因为我正在使用递归(如果当前子节点不是文本节点,请在该子节点上调用我的函数,将其用作父节点)。令人困惑,但非常有效。

希望这可以帮助!

于 2019-01-07T20:35:54.877 回答