【问题标题】:Replace text with link with chrome extension用带有 chrome 扩展名的链接替换文本
【发布时间】:2016-10-27 04:30:59
【问题描述】:

我正在尝试用链接替换网页上的文本。当我尝试这个时,它只是用标签而不是链接替换文本。例如,此代码将“河流”替换为:

<a href="http://www.cnn.com">asdf</a>

这是我目前所拥有的:

function handleText(textNode)
{
    var v = textNode.nodeValue;
    v = v.replace(/\briver\b/g, '<a href="http://www.cnn.com">asdf</a>');
    textNode.nodeValue = v;
}

【问题讨论】:

  • 您必须分配给 textnode 父节点的 innerHTML
  • textNode 实际上是一个 TEXT 节点吗?如果是这样,则文本节点没有子节点,并且您不能仅通过分配您尝试这样做的方式来创建&lt;a&gt;。您正试图将其视为正常元素。我们是假设您正在传递一个实际的文本节点(即textNode.nodeName === '#text'),还是您希望将任何类型的元素传递给handleText()

标签: javascript google-chrome-extension


【解决方案1】:

如果您只想将文本更改为其他纯文本,那么您可以直接更改文本节点的内容。但是,您想要添加一个 &lt;a&gt; 元素。对于您要添加的每个 &lt;a&gt; 元素,您实际上是想要添加一个子元素。文本节点不能有子节点。因此,要做到这一点,您实际上必须用更复杂的结构替换文本节点。这样做时,您将希望对 DOM 产生尽可能小的影响,以免干扰依赖于 DOM 当前结构的其他脚本。影响不大的最简单方法是将文本节点替换为 &lt;span&gt;,其中包含新的文本节点(文本将围绕新的 &lt;a&gt; 拆分)和任何新的 &lt;a&gt; 元素。

下面的代码应该可以满足您的需求。它将textNode 替换为包含新文本节点和创建的&lt;a&gt; 元素的&lt;span&gt;。它仅在需要插入一个或多个&lt;a&gt; 元素时进行替换。

function handleTextNode(textNode) {
    if(textNode.nodeName !== '#text'
        || textNode.parentNode.nodeName === 'SCRIPT' 
        || textNode.parentNode.nodeName === 'STYLE'
    ) {
        //Don't do anything except on text nodes, which are not children 
        //  of <script> or <style>.
        return;
    }
    let origText = textNode.textContent;
    let newHtml=origText.replace(/\briver\b/g,'<a href="http://www.cnn.com">asdf</a>');
    //Only change the DOM if we actually made a replacement in the text.
    //Compare the strings, as it should be faster than a second RegExp operation and
    //  lets us use the RegExp in only one place for maintainability.
    if( newHtml !== origText) {
        let newSpan = document.createElement('span');
        newSpan.innerHTML = newHtml;
        textNode.parentNode.replaceChild(newSpan,textNode);
    }
}

//Testing: Walk the DOM of the <body> handling all non-empty text nodes
function processDocument() {
    //Create the TreeWalker
    let treeWalker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT,{
        acceptNode: function(node) { 
            if(node.textContent.length === 0) {
                //Alternately, could filter out the <script> and <style> text nodes here.
                return NodeFilter.FILTER_SKIP; //Skip empty text nodes
            } //else
            return NodeFilter.FILTER_ACCEPT;
        }
    }, false );
    //Make a list of the text nodes prior to modifying the DOM. Once the DOM is 
    //  modified the TreeWalker will become invalid (i.e. the TreeWalker will stop
    //  traversing the DOM after the first modification).
    let nodeList=[];
    while(treeWalker.nextNode()){
        nodeList.push(treeWalker.currentNode);
    }
    //Iterate over all text nodes, calling handleTextNode on each node in the list.
    nodeList.forEach(function(el){
        handleTextNode(el);
    });
} 
document.getElementById('clickTo').addEventListener('click',processDocument,false);
<input type="button" id="clickTo" value="Click to process"/>
<div id="testDiv">This text should change to a link -->river<--.</div>

TreeWalker 代码取自my answer here

【讨论】:

  • 效果很好,谢谢!如果我想替换“river”和“stream”并将它们链接到两个不同的网站怎么办?这将如何运作?
  • 我很高兴能够提供帮助。如何进行第二次替换将取决于您希望 handleText 函数的通用性。如果它是您一直想要执行的静态替换(如您的 river 替换),则很容易在 let newHtml ... 之后添加一条语句,即 newHtml = newHtml.replace(/\bstream\b/g, ...`。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-17
  • 2022-01-21
  • 1970-01-01
  • 2010-09-13
  • 1970-01-01
  • 2012-04-24
  • 2011-08-13
相关资源
最近更新 更多