【问题标题】:Replace method adding <strong>$1</strong> instead of the matched substring and bold text替换方法添加 <strong>$1</strong> 而不是匹配的子字符串和粗体文本
【发布时间】:2021-08-08 23:13:08
【问题描述】:

以下代码记录正在按下哪些键。如果前两个键与链接中的前两个字符匹配,则这些字符将突出显示。 (在这种情况下,“li”来自“link”。)

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }

    element.textContent = element.textContent.replace(text, `<strong>$1</strong>`)
  }
})
&lt;a href="#"&gt;link&lt;/a&gt;

我想用&lt;strong&gt;标签突出显示字符。

我期待这个:

link

但我得到了这个:

<strong>$1</strong>nk

步骤:

  1. 按“运行代码 sn-p”
  2. 输入l,然后输入i

【问题讨论】:

  • 您将替换 textContent 用于文本,而不是用于 HTML。
  • 另外,$1 用于正则表达式作为搜索条件,而不是字符串,因为字符串不能有捕获组。您可以使用$&amp;,也可以使用函数:.replace(text, s =&gt; `&lt;strong&gt;${s}&lt;/strong&gt;`)
  • 这种方法也有其他缺点,例如不考虑标签之间的匹配或破坏事件侦听器和标签引用。您可能会考虑为此目的使用库,例如​​ markjs.io
  • 不需要图书馆。 DOM API 有多种文本节点的方法。我写了一些关于Finding and replacing parts of a documenthighlighting text in a document 的答案。
  • 只需连接按键字符串 searchText =''; searchText += event.key;而不是推送到数组并调用 join;

标签: javascript html


【解决方案1】:

至少有 2 个问题:首先,您将 html 插入到 textContent,它作为文本而不是 html 插入。其次,由于您在搜索中没有捕获组,因此您不能使用$1,而是可以使用${text}$&amp;

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }
    element.innerHTML = element.innerHTML.replace(text, `<strong>$&</strong>`)
  }
})
&lt;a href="#"&gt;link&lt;/a&gt;

这是一个不影响html的“更安全”的版本:

let keys = []

document.addEventListener('keypress', event => {
  keys.push(event.key)

  console.log(keys)

  const selector = 'a'
  let text = keys.join('')
  let element = [...document.querySelectorAll(selector)]
    .find(elements => elements.textContent.includes(text))

  if (keys.length === 2) {
    if (!element) {
      keys = []
      return
    }


    //make it html friendly
    text = text.replace(/&/g, "&amp;")
               .replace(/</g, "&lt;")
               .replace(/>/g, "&gt;")
                //make it regex friendly
               .replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');

    element.innerHTML = element.innerHTML
                  //remove old highlightings
                  .replace(/<mark>([^<]*)?<\/mark>/g, "$1")
                  // convert selected text into regex,
                  // search and enclose found strings with <mark></mark>
                  .replace(new RegExp("(" + text + ")", "gi"), '<mark>$1</mark>'); //add new highlighting
  }
})
mark
{
  background-color: inherit;
  font-weight: bold;
}
<a href="#">link</a>
<a href="#">href</a>

【讨论】:

  • 请注意,如果匹配的一部分是 HTML 实体,这将无法正常工作。尝试匹配 Mac &amp;amp; Cheese - 它不会被替换,因为在 HTML 中它是 Mac &amp;amp; Cheese。仅仅在匹配部分用 innerHTML 替换 textContent 也是不够的,因为它还可以匹配标签和属性的中间部分。
  • 这种方法只适用于前 2 个按键。如果标记存在,则需要在每次按键时删除您注入的 ... 全部删除
  • @dMd 这是 OP 必须决定的事情,它不是原始问题的一部分。
  • 非常完整的答案。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-12-12
  • 1970-01-01
  • 1970-01-01
  • 2012-01-19
  • 1970-01-01
  • 2018-04-15
  • 2019-03-18
相关资源
最近更新 更多