如何在span标记中包装DOM关键字

问题描述 投票:1回答:1

我正在编写一个JavaScript脚本,它将遍历DOM并将特定关键字包装在<span>标记中。我希望我的scriptpan中包装<span>这个词的任何出现,所以我可以使用<span style='color: red'来设置它。我实际上并不想使用pan这个词,我只是以它为例。

我已经在这里审查了很多类似的帖子,但没有一个能解决我的问题。大多数是核,过于复杂和混乱,或过度简化,并没有像我想要的那样工作。

这是我到目前为止所写的内容:

<html>
  <body>
    <p>My <span style='font-weight: bold'>favorite</span> kitchen item is the pan.</p>
    <p>A pan can also be used as a weapon.</p>
    <script>
      // walk the document body
      function walk (node) {
        // if text node
        if (node.nodeType == 3) {
          // will always be an element
          const parent = node.parentNode;
          
          // ignore script and style tags
          const tagName = parent.tagName;
          if (tagName !== 'SCRIPT' && tagName !== 'STYLE') {
            
            // wrap occurrences of 'pan' in a red `<span>` tag
            const span = '<span style="color: red">pan</span>';
            parent.innerHTML = parent.innerHTML.replace (/pan/g, span)
          }
        }
        node = node.firstChild;
        while (node) {
          walk (node);
          node = node.nextSibling;
        }
      }
      walk (document.body)
    </script>
  </body>
</html>

此代码大多数时间都按预期运行。但是,在这个例子中,它没有。如果您要运行此代码,this将是结果。

我知道造成这种情况的原因。但是,我不知道如何解决它。

其中两个文本节点Mykitchen item is the pan.有一个父元素,其中包含以下innerHTMLMy <span style="font-weight: bold">favorite</span> kitchen item is the pan. <span>中的“pan”正在被替换,并导致问题。

如果我使用parentNode.textContent而不是parentNode.innerHTML,它不会将其包装在<span>标签中,它会将其作为可见文本插入。

我知道这可以通过将/pan/g更改为/\bpan\b/g来解决,但这只能修复我创建的这个示例。我需要将<span>标记仅插入到文本内容中,而不是标记名称或其他HTML。

我该怎么办?

javascript html css dom nodes
1个回答
2
投票

使用转义搜索字符串搜索给定的htmlString。这样做(通过适当的转义)将有助于避免匹配HTML标记(例如<span>)或子字符串(例如Pandora)之类的问题。

/*
highlight(selector, string)
@ Params:
  selector [String]: Same syntax as CSS/jQuery selector
  string   [String]: Seach string
*/
// A: Get the htmlString of the target's content
// B: Escape the search string
// C: Create a RegExp Object of the escaped search string
// D: Find and replace all matches with match wrapped in a <mark>
// E: Remove original HTML
// F: Insert new HTML
function highlight(selector, string) {
  let dom = document.querySelector(selector);
  let str = dom.innerHTML; //A
  let esc = `(?!(?:[^<]+>|[^>]+<\\/a>))\\b(${string})\\b`; //B
  let rgx = new RegExp(esc, "gi"); //C
  let txt = str.replace(rgx, `<mark>$1</mark>`); //D
  dom.innerHTML = ''; //E 
  dom.insertAdjacentHTML('beforeend', txt); //F
}

highlight('body', "pan");
<html>

<body>
  <p>My <span style='font-weight: bold'>favorite</span> kitchen item is the pan.</p>
  <p>A pan can also be used as a weapon.</p>
  <p>Pan was the Greek god of the wild.</p>
  <p>Eboli was breifly a pandemic threat.</p>

</body>

</html>
© www.soinside.com 2019 - 2024. All rights reserved.