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

7

我想在文本主体中突出显示所有匹配的单词,但不包括任何 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()来实现,但我对正则表达式了解不多。

1
问题类似于:https://dev59.com/XnVD5IYBdhLWcg3wAWoO - Yzmir Ramirez
1
“在 HTML 标签内部但不包括标签名、属性名或属性值中的任何单词。” - 为了澄清,您的意思是指元素内容中的单词,而不是元素标记、属性名称或属性值中的单词? - nnnnnn
不要使用正则表达式来尝试解析和修改HTML原始代码。使用DOM,这样您只会触及实际的文本节点。(请参见我的答案。) - Phrogz
3个回答

16

演示: 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
我可以问一下如何从HTML <p id="root">......</p> 和 <p id="word">......</p> 传递值到JavaScript吗?因为您的解决方案是手动输入高亮词语,例如“highlightWord(document.body,'para');”。我该如何更改为自动突出显示高亮词(<p id="word">para</p>)在<p id="root">这里是一个段落内部,关于滑翔伞。</p>中。 - bob90937

6

为什么使用自制的高亮功能是不好的

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

  • 您需要删除带有HTML元素的文本节点,以便在不破坏DOM事件和反复触发DOM重建的情况下突出显示匹配项(例如innerHTML
  • 如果要删除突出显示的元素,则必须删除带有其内容的HTML元素,并且还必须组合分裂的文本节点以进行进一步的搜索。这是必要的,因为每个高亮插件都会在文本节点中搜索匹配项,如果您的关键字被分割成几个文本节点,则无法找到它们。
  • 您还需要构建测试,以确保您的插件在您没有考虑的情况下工作。我说的是跨浏览器测试!

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

使用现有的插件

使用现有的、良好实现的插件时,您不必担心上述命名的问题。Sitepoint上的10个jQuery文本高亮插件文章比较了流行的高亮插件。

看看mark.js

mark.js是一个使用纯JavaScript编写的插件,但也可用作jQuery插件。它的开发旨在提供比其他插件更多的机会,包括以下选项:

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

演示

或者您可以查看这个fiddle

使用示例

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

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

这是一个免费的IT技术项目,源代码在GitHub上开放并进行了开发(项目参考)。


0

你可以使用正则表达式的方法,但它目前不能突出显示多个标签。 例如,如果要突出显示“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>");
})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接