使用 jQuery 突出显示单词

IT技术 javascript jquery html
2021-01-14 13:09:14

我基本上需要突出显示文本块中的特定单词。例如,假设我想在本文中突出显示“dolor”一词:

<p>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer dolor ullamcorper libero.
    Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

我如何将上述内容转换为这样的:

<p>
    Lorem ipsum <span class="myClass">dolor</span> sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer <span class="myClass">dolor</span> ullamcorper
    libero. Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

这可以用 jQuery 实现吗?

编辑:正如塞巴斯蒂安 指出的那样,这在没有 jQuery 的情况下很有可能 - 但我希望可能有一种特殊的 jQuery 方法可以让您对文本本身进行选择器。我已经在这个站点上大量使用 jQuery,因此将所有内容都包含在 jQuery 中可能会使事情更整洁一些。

6个回答

试试highlight: JavaScript text highlighting jQuery plugin警告 - 此页面上可用的源代码包含加密货币挖掘脚本,请使用下面的代码或从网站上的下载中删除挖掘脚本。

/*

highlight v4

Highlights arbitrary terms.

<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>

MIT license.

Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>

*/

jQuery.fn.highlight = function(pat) {
 function innerHighlight(node, pat) {
  var skip = 0;
  if (node.nodeType == 3) {
   var pos = node.data.toUpperCase().indexOf(pat);
   if (pos >= 0) {
    var spannode = document.createElement('span');
    spannode.className = 'highlight';
    var middlebit = node.splitText(pos);
    var endbit = middlebit.splitText(pat.length);
    var middleclone = middlebit.cloneNode(true);
    spannode.appendChild(middleclone);
    middlebit.parentNode.replaceChild(spannode, middlebit);
    skip = 1;
   }
  }
  else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
   for (var i = 0; i < node.childNodes.length; ++i) {
    i += innerHighlight(node.childNodes[i], pat);
   }
  }
  return skip;
 }
 return this.length && pat && pat.length ? this.each(function() {
  innerHighlight(this, pat.toUpperCase());
 }) : this;
};

jQuery.fn.removeHighlight = function() {
 return this.find("span.highlight").each(function() {
  this.parentNode.firstChild.nodeName;
  with (this.parentNode) {
   replaceChild(this.firstChild, this);
   normalize();
  }
 }).end();
};

还可以尝试原始脚本“更新”版本

/*
 * jQuery Highlight plugin
 *
 * Based on highlight v3 by Johann Burkard
 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
 *
 * Code a little bit refactored and cleaned (in my humble opinion).
 * Most important changes:
 *  - has an option to highlight only entire words (wordsOnly - false by default),
 *  - has an option to be case sensitive (caseSensitive - false by default)
 *  - highlight element tag and class names can be specified in options
 *
 * Usage:
 *   // wrap every occurrance of text 'lorem' in content
 *   // with <span class='highlight'> (default options)
 *   $('#content').highlight('lorem');
 *
 *   // search for and highlight more terms at once
 *   // so you can save some time on traversing DOM
 *   $('#content').highlight(['lorem', 'ipsum']);
 *   $('#content').highlight('lorem ipsum');
 *
 *   // search only for entire word 'lorem'
 *   $('#content').highlight('lorem', { wordsOnly: true });
 *
 *   // don't ignore case during search of term 'lorem'
 *   $('#content').highlight('lorem', { caseSensitive: true });
 *
 *   // wrap every occurrance of term 'ipsum' in content
 *   // with <em class='important'>
 *   $('#content').highlight('ipsum', { element: 'em', className: 'important' });
 *
 *   // remove default highlight
 *   $('#content').unhighlight();
 *
 *   // remove custom highlight
 *   $('#content').unhighlight({ element: 'em', className: 'important' });
 *
 *
 * Copyright (c) 2009 Bartek Szopka
 *
 * Licensed under MIT license.
 *
 */

jQuery.extend({
    highlight: function (node, re, nodeName, className) {
        if (node.nodeType === 3) {
            var match = node.data.match(re);
            if (match) {
                var highlight = document.createElement(nodeName || 'span');
                highlight.className = className || 'highlight';
                var wordNode = node.splitText(match.index);
                wordNode.splitText(match[0].length);
                var wordClone = wordNode.cloneNode(true);
                highlight.appendChild(wordClone);
                wordNode.parentNode.replaceChild(highlight, wordNode);
                return 1; //skip added node in parent
            }
        } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
            for (var i = 0; i < node.childNodes.length; i++) {
                i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
            }
        }
        return 0;
    }
});

jQuery.fn.unhighlight = function (options) {
    var settings = { className: 'highlight', element: 'span' };
    jQuery.extend(settings, options);

    return this.find(settings.element + "." + settings.className).each(function () {
        var parent = this.parentNode;
        parent.replaceChild(this.firstChild, this);
        parent.normalize();
    }).end();
};

jQuery.fn.highlight = function (words, options) {
    var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
    jQuery.extend(settings, options);

    if (words.constructor === String) {
        words = [words];
    }
    words = jQuery.grep(words, function(word, i){
      return word != '';
    });
    words = jQuery.map(words, function(word, i) {
      return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    });
    if (words.length == 0) { return this; };

    var flag = settings.caseSensitive ? "" : "i";
    var pattern = "(" + words.join("|") + ")";
    if (settings.wordsOnly) {
        pattern = "\\b" + pattern + "\\b";
    }
    var re = new RegExp(pattern, flag);

    return this.each(function () {
        jQuery.highlight(this, re, settings.element, settings.className);
    });
};
重要提示:Johann Burkard 在其网站上提供的源代码中包含了一个挖掘脚本!!!!!!
2021-03-13 13:09:14
有两种解决方案,它们分别包含在一个文件中。我在上面添加了它们。至少,在最坏的情况下,它们将始终在编辑历史记录中可用。
2021-03-23 13:09:14
顺便说一下,这里的 <mark>-tag 可能比 <span> 标签更好。
2021-04-02 13:09:14
如果您正在寻找小巧轻便的产品,highlight jquery 插件确实是您的最佳选择。它非常适合突出显示和删除与给定文本匹配的突出显示。如果您需要正则表达式或其他支持;但是,请查看 mark.js 或任何用于从高亮页面链接到的高亮扩展和分支。我使用突出显示自己而不是其他人,因为轻量级受到高度赞赏。
2021-04-05 13:09:14
highlight v4 有点问题。Burkard的主页上有一个修复程序: johannburkard.de/blog/programming/javascript/...在这种情况下,将代码复制到这里不是一个好主意;链接指向最新版本(现在:))。
2021-04-06 13:09:14
function hiliter(word, element) {
    var rgxp = new RegExp(word, 'g');
    var repl = '<span class="myClass">' + word + '</span>';
    element.innerHTML = element.innerHTML.replace(rgxp, repl);
}
hiliter('dolor');
您不想使用innerHTML,因为它是由Microsoft 在80 年代引入的,后来又像往常一样被Microsoft 放弃了。尽管大多数浏览器都支持它,但它只是 W3C 标准之外的一切。
2021-03-12 13:09:14
不是一个很好的解决方案。我只是使用了这个,但是如果我搜索例如“person”,它也会用“person”替换所有类和 html 元素。而且小写和大写也没有整合。var rgxp = new RegExp("(\\b" + word + "\\b)", "gim"); 修复了这个问题,但我认为代码不应该替换 html 元素。
2021-03-14 13:09:14
@Sir Ben Benji:我认为您将innerHTML 与innerText(Microsoft 开发的textContent 替代品,这确实是规范的诅咒)混淆了。innerHTML 可能是作为 Microsoft 扩展开始的,但绝不会被“丢弃”;自 2000 年初以来,每个主要浏览器都支持它,并且是 HTML5 的一部分(早在 2008 年):w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml它仍然存在于最新版本中在w3.org/TR/DOM-Parsing修订另见w3.org/TR/html5/references.html#refsDOMPARSING
2021-03-31 13:09:14
你应该用什么来代替innerHTML?
2021-04-01 13:09:14

为什么使用自制的高亮功能是个坏主意

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

  • 您需要删除带有 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);

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

这是一个忽略并保留大小写的变体:

jQuery.fn.highlight = function (str, className) {
    var regex = new RegExp("\\b"+str+"\\b", "gi");

    return this.each(function () {
        this.innerHTML = this.innerHTML.replace(regex, function(matched) {return "<span class=\"" + className + "\">" + matched + "</span>";});
    });
};
innerHTML是邪恶的,请在此处查看我的答案。此外,\\b不适用于 unicode 字符。此外,此函数几乎会遗漏任何内容,例如在嵌套子项中搜索。
2021-03-25 13:09:14
这适用于纯文本,但它似乎不排除标签和属性。即,当您的innerHTML 中的div 上有一个class 属性时,搜索“lass”。
2021-03-27 13:09:14
这个函数是怎么调用的?
2021-03-28 13:09:14

JSFiddle

用途.each(), .replace(), .html(). 使用 jQuery 1.11 和 3.2 测试。

在上面的示例中,读取要突出显示的 'keyword' 并附加带有 'highlight' 类的 span 标签。文本“关键字”在.each().

HTML

<body>
   <label name="lblKeyword" id="lblKeyword" class="highlight">keyword</label>
   <p class="filename">keyword</p>
   <p class="content">keyword</p>
   <p class="system"><i>keyword</i></p>
</body>

JS

$(document).ready(function() {
   var keyWord = $("#lblKeyword").text(); 
   var replaceD = "<span class='highlight'>" + keyWord + "</span>";
   $(".system, .filename, .content").each(function() {
      var text = $(this).text();
      text = text.replace(keyWord, replaceD);
      $(this).html(text);
   });
});

CSS

.highlight {
    background-color: yellow;
}