gpt4 book ai didi

javascript - 使用.replace()在页面上突出显示一个单词

转载 作者:行者123 更新时间:2023-11-29 10:33:37 25 4
gpt4 key购买 nike

我正在开发Google Chrome扩展程序,该扩展程序可让您将突出显示的CSS规则自动应用于您选择的单词。

我有以下代码

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 fetchedText = text.match(/teste/gi);

if(fetchedText) {
var replacedText = element.innerHTML.replace(/(teste)/gi, "<span style=\"background-color: yellow\">$1</span>");

if (replacedText !== text) {
element.innerHTML = replacedText;
}
}
}
}
}

这会中断并冻结我的Chrome标签。但是,如果我从 element.innerHTML = replacedText;切换到 element.innerHTML = "text";,则可以使用。

我似乎找不到以下代码有什么问题。

最佳答案

您首先要测试#text节点,以查看文本是否包含要突出显示的单词,然后对父元素的.innerHTML进行替换。这有两个问题。

  • 无限替换:修改父元素的.innerHTML时,将更改childNodes数组。这样做的方式是在包含要替换文本的数组中进一步添加了一个节点。因此,当您继续扫描childNodes数组时,总是会找到一个(新的)节点,其中包含要替换的文本。因此,再次替换它,在childNodes数组中创建另一个具有较高索引的节点。无限重复。
  • 使用RegExp替换.innerHTML属性中的文本。虽然已经进行测试以确保要替换的文本实际上包含在文本节点中,但这不会阻止RegExp也替换元素的实际HTML中的任何匹配单词(例如src="yourWord"href="http://foo.com/yourWord/bar.html"或尝试突出显示stylecolorbackgroundspanidheightwidthbuttonforminput等词。)。
  • 您无需检查以确保未更改<script><style>标记中的文本。
  • 您正在检查仅在文本节点中进行了更改(即,检查node.nodeType === 3)。如果不进行检查,由于使用.innerHTML更改HTML,您还将遇到以下可能的问题:
  • 根据.replace()所做的更改,您最终可能会更改属性或实际的HTML标签。这可能会完全破坏页面布局和功能。
  • 更改.innerHTML时,将完全重新创建页面那部分的DOM。这意味着元素,尽管新元素可能是具有相同属性的相同类型,但是附加到旧元素的任何事件侦听器都不会附加到新元素。这会严重破坏页面的功能。
  • 重复更改DOM的大部分可能需要大量的计算才能重新呈现页面。根据您执行此操作的方式,您可能会遇到用户认为严重的性能问题。

  • 因此,如果要使用RegExp替换文本,则只需要对 #text节点的内容执行操作,而不需要对父节点的 .innerHTML进行操作。因为您要创建其他HTML元素(例如,带有子 <span style="">节点的新 #text元素),所以会有些复杂。

    无法将HTML文本分配给文本节点以创建新的HTML节点:

    无法将新的HTML直接分配给文本节点并将其评估为HTML,从而创建新的节点。分配给文本节点的 .innerHTML属性将在Object上创建此类属性(就像在任何Object上一样),但不会更改屏幕上显示的文本(即 #text节点的实际值)。因此,它将无法完成您想要做的事情:它将不会创建父节点的任何新HTML子代。

    这样做对页面DOM的影响最小(即,最不可能破坏页面上现有JavaScript的方式)的方法是创建 <span>,以包括您正在创建的新文本节点( #text节点中的文本不在您的彩色 <span>中)以及您正在创建的可能有多个 <span>元素中。这将导致用单个 #text元素替换单个 <span>节点。虽然这将创建其他后代,但将使父元素中的子代数保持不变。因此,任何依赖它的JavaScript都不会受到影响。鉴于我们正在更改DOM,因此没有办法可能不会破坏其他JavaScript,但这应将这种可能性降到最低。

    有关如何执行此操作的一些示例:有关执行正则表达式的完整扩展,请参见 this answer(将按钮中的单词替换为单词列表)和 this answer(将ozt_code元素中的所有文本(由空格分隔)放置在按钮中),以获取使用新HTML进行正则表达式替换的完整扩展。请参阅 this answer,它基本上具有相同的功能,但是建立了链接(它具有不同的实现,该实现通过 TreeWalker遍历DOM以查找 <p>节点,而不是其他两个示例中使用的 NodeIterator)。

    这是将在 #text中的每个文本节点上执行所需替换的代码,并创建新的HTML,以使 document.body在文本的一部分中有所不同:
    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(/(teste)/gi
    ,'<span style="background-color: yellow">$1</span>');
    //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);
    }
    }

    let textNodes = [];
    //Create a NodeIterator to get the text nodes in the body of the document
    let nodeIter = document.createNodeIterator(document.body,NodeFilter.SHOW_TEXT);
    let currentNode;
    //Add the text nodes found to the list of text nodes to process.
    while(currentNode = nodeIter.nextNode()) {
    textNodes.push(currentNode);
    }
    //Process each text node
    textNodes.forEach(function(el){
    handleTextNode(el);
    });

    还有其他方法可以做到这一点。但是,它们将对该特定元素(例如,父级上的多个其他节点)的子级结构产生更重大的变化。这样做有很大的可能破坏依赖于页面当前结构的页面上已有的JavaScript。实际上,任何这样的更改都有可能破坏当前的JavaScript。

    此答案中的代码已从 this other answer of mine中的代码修改而来

    关于javascript - 使用.replace()在页面上突出显示一个单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40710728/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com