突出显示 HTML 文本中的单词(但不突出显示标记)

Highlight word in HTML text (but not markup)

提问人:Iswanto Arif 提问时间:5/24/2012 最后编辑:PhrogzIswanto Arif 更新时间:5/20/2016 访问量:11799

问:

我试图突出显示正文中所有匹配的单词,而不是任何 html 标签中的单词。例如,给出的关键字是“para”。这是一段:

<p class="para"> Example of paragraph. Lorem ipsum dolor sit amet. </p>

导致:

<p class="para">
Example of <strong>para</strong>graph. Lorem ipsum dolor sit amet.
</p>

我知道这在 JavaScript 中是可能的,但我只是对正则表达式知之甚少。replace()

JavaScript 正则表达式

评论

1赞 Yzmir Ramirez 5/24/2012
问题类似于:stackoverflow.com/questions/119441/highlight-a-word-with-jquery
1赞 nnnnnn 5/24/2012
“inside the body but not words inside any html tag” - 澄清一下,您的意思是任何元素内容中的单词,而不是元素标记名称、属性名称或属性值?
0赞 Phrogz 5/24/2012
您不希望使用正则表达式来尝试解析和更改 HTML 原始源代码。使用 DOM,以便仅触摸实际的文本节点。(看我的回答。

答:

16赞 Phrogz 5/24/2012 #1

演示:http://jsfiddle.net/crgTU/7/

highlightWord(document.body,'para');

function highlightWord(root,word){
  textNodesUnder(root).forEach(highlightWords);

  function textNodesUnder(root){
    var n,a=[],w=document.createTreeWalker(root,NodeFilter.SHOW_TEXT,null,false);
    while(n=w.nextNode()) a.push(n);
    return a;
  }

  function highlightWords(n){
    for (var i; (i=n.nodeValue.indexOf(word,i)) > -1; n=after){
      var after = n.splitText(i+word.length);
      var highlighted = n.splitText(i);
      var span = document.createElement('span');
      span.className = 'highlighted';
      span.appendChild(highlighted);
      after.parentNode.insertBefore(span,after);
    }
  }
}
​

您也可以考虑调用类似...

function removeHighlights(root){     
  [].forEach.call(root.querySelectorAll('span.highlighted'),function(el){
    el.parentNode.replaceChild(el.firstChild,el);
  });
}

...在查找新高亮之前(从 DOM 中删除旧高亮)。

评论

1赞 bob90937 11/4/2016
我可以问如何从html传递值<p id=“root”吗> .....</p> 和 <p id=“word”>......</p> 到 javascripe???因为您的解决方案是手动键入突出显示词,例如“ highlightWord(document.body,'para');”我怎样才能在 <p id=“root”>> 中更改为自动突出显示突出显示术语( <p id=“word”>para</p这是在一段关于滑翔伞的段落中</p>
0赞 HMR 10/19/2012 #2

您可以使用正则表达式方式,但它不会在多个标签上突出显示。 对于 exampel myhighlight,不会突出显示“my highlights”一词。

代码如下:

str='<img src="brown fox.jpg" title="The brown fox" />'
    +'<p>some text containing fox. And onother fox.</p>'
var word="fox";
word="(\\b"+ 
    word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1")
        + "\\b)";
var r = new RegExp(word,"igm")
str.replace(/(>[^<]+)/igm,function(a){
    return a.replace(r,"<span class='hl'>$1</span>");
})
6赞 dude 1/19/2016 #3

为什么使用自制的突出显示功能是个坏主意

从头开始构建自己的高亮功能可能是一个坏主意的原因是因为您肯定会遇到其他人已经解决的问题。挑战:

  • 您需要删除带有 HTML 元素的文本节点以突出显示您的匹配项,而不会破坏 DOM 事件并一遍又一遍地触发 DOM 重新生成(例如,这种情况就是这种情况innerHTML)
  • 如果要删除突出显示的元素,则必须删除 HTML 元素及其内容,并且还必须组合拆分的文本节点以进行进一步搜索。这是必要的,因为每个荧光笔插件都会在文本节点内搜索匹配项,如果您的关键字将被拆分为多个文本节点,则不会找到它们。
  • 您还需要构建测试以确保您的插件在您没有想到的情况下工作。我说的是跨浏览器测试!

听起来很复杂?如果您想要一些功能,例如忽略突出显示、变音符号映射、同义词映射、iframe 内部搜索、分隔单词搜索等元素,这将变得越来越复杂。

使用现有插件

当使用现有的、实施良好的插件时,您不必担心上面提到的问题。文章 Sitepoint 上的 10 个 jQuery 文本荧光笔插件比较了流行的荧光笔插件。

一看马克.js

mark.js就是这样一个用纯JavaScript编写的插件,但也可以作为jQuery插件使用。它的开发是为了提供比其他插件更多的机会,并提供以下选项:

  • 单独搜索关键字,而不是搜索完整的术语
  • 地图变音符号(例如,如果“justo”也应匹配“justò”)
  • 忽略自定义元素中的匹配项
  • 使用自定义突出显示元素
  • 使用自定义突出显示类
  • 映射自定义同义词
  • 同时在 iframe 中搜索
  • 接收未找到的字词

演示

或者,您可以看到这把小提琴

使用示例

// Highlight "keyword" in the specified context
$(".context").mark("keyword");

// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);

它是免费的,在 GitHub 上开源开发(项目参考)。