Выделите слово с помощью jQuery


101

Мне в основном нужно выделить определенное слово в блоке текста. Например, представьте, что я хочу выделить слово «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, это, возможно, сделает вещи немного более аккуратными.


Это также может быть интересно: jquery.info/The-plugin-SearchHighlight
Eikern

Привет, я написал плагин, который делает именно это - он похож на плагин Иоганна Буркарда mlarsen, но работает с регулярными выражениями вместо строк. Проверьте это на github и дайте мне знать, если вам нужны дополнительные функции.

3
Если вам нужна мягкая версия плагина jQuery highlight: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör

1
С точки зрения семантики, вместо выделения слов с помощью a <span>, более правильно использовать <mark>.
Хосе Руи Сантос,

Привет, я опоздал на борт, но вот еще один фрагмент кода, который помогает выделять и фильтровать текст на основе тегов. Надеюсь, это поможет кому-то плагин jQuery для выделения текста и фильтрации
Джасприт Чахал

Ответы:


85

Попробуйте выделить: Подсветка текста JavaScript, плагин jQuery .! Предупреждение. Исходный код, доступный на этой странице, содержит скрипт майнинга криптовалюты, либо используйте приведенный ниже код, либо удалите скрипт майнинга из загрузки на веб-сайте. !

/*

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);
    });
};

Есть два решения, каждое из которых содержится в одном файле. Я добавил их выше. По крайней мере, в худшем случае они всегда будут доступны здесь в истории редактирования.
Эрик Робертсон

Highlight v4 немного глючит. На домашней странице Burkard есть исправление: johannburkard.de/blog/programming/javascript/… В данном случае копировать код здесь было не очень хорошей идеей; ссылка указывает на последнюю версию (сейчас :)).
Лерин Сонберг,

Кстати, тег <mark>, вероятно, здесь лучше, чем тег <span>.
unitario

1
Если вы ищете небольшой и легкий плагин для jquery, действительно ваш лучший выбор. Он отлично подходит для выделения и удаления выделения, соответствующего данному тексту. Если вам нужно регулярное выражение или другая поддержка; тем не менее, проверьте mark.js или любое из расширений и вилок для выделения, на которое есть ссылка на странице выделения. Я использую выделение себя по сравнению с другими, потому что очень ценен легкий вес.
Грег

3
ВАЖНО: Иоганн Буркард включил скрипт майнинга в источник, представленный на своем сайте !!!!!!
Lukars

42
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');

2
Вы не хотите использовать innerHTML, поскольку он был введен Microsoft в 80-х годах, а затем снова отказался от Microsoft, как обычно. Несмотря на то, что большинство браузеров его поддерживают, это все, кроме стандарта W3C.
Стив К,

21
Что использовать вместо innerHTML?
Кебман

15
@ Сэр Бен Бенджи: Я думаю, вы путаете 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
Джей Дансанд,

1
Не очень хорошее решение. Я просто использовал это, но если я ищу, например, «человек», он также заменяет все классы и элементы html на «человек». И строчные и прописные буквы тоже не интегрированы. var rgxp = new RegExp ("(\\ b" + word + "\\ b)", "gim"); исправил это, но все же я думаю, что код не должен заменять элементы html.
Ричард Линдхаут, 01

33

Почему использовать самодельную функцию выделения - плохая идея

Причина, по которой, вероятно, плохая идея начинать создавать свою собственную функцию выделения с нуля, заключается в том, что вы наверняка столкнетесь с проблемами, которые другие уже решили. Проблемы:

  • Вам нужно будет удалить текстовые узлы с элементами HTML, чтобы выделить ваши совпадения, не разрушая события DOM и не запуская регенерацию DOM снова и снова (что было бы в случае, например innerHTML)
  • Если вы хотите удалить выделенные элементы, вам придется удалить элементы HTML с их содержимым, а также объединить разделенные текстовые узлы для дальнейшего поиска. Это необходимо, потому что каждый плагин подсветки ищет совпадения внутри текстовых узлов, и если ваши ключевые слова будут разделены на несколько текстовых узлов, они не будут найдены.
  • Вам также потребуется создать тесты, чтобы убедиться, что ваш плагин работает в ситуациях, о которых вы не задумывались. И я говорю о кроссбраузерных тестах!

Звучит сложно? Если вам нужны некоторые функции, такие как игнорирование некоторых элементов выделения, отображение диакритических знаков, сопоставление синонимов, поиск внутри iframe, поиск по отдельным словам и т. Д., Это становится все более и более сложным.

Использовать существующий плагин

При использовании существующего, хорошо реализованного плагина вам не нужно беспокоиться о вышеупомянутых вещах. В статье 10 подключаемых модулей выделения текста jQuery на Sitepoint сравниваются популярные подключаемые модули выделения текста . Сюда входят плагины ответов на этот вопрос.

Взгляните на mark.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 ( ссылка на проект ).


11

Вот вариант, который игнорирует и сохраняет регистр:

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>";});
    });
};

6
Это работает для простого текста, но не исключает теги и атрибуты. т.е. ищите "lass", когда у вас есть атрибут class в div в вашем innerHTML.
Джонатан

Как вызывается эта функция?
jiy

innerHTMLзло, см. мой ответ здесь. Кроме того, \\bне работает для символов Юникода. Кроме того, эта функция пропускает почти все, например поиск внутри вложенных дочерних элементов.
чувак

3

Вы можете использовать следующую функцию, чтобы выделить любое слово в тексте.

function color_word(text_id, word, color) {
    words = $('#' + text_id).text().split(' ');
    words = words.map(function(item) { return item == word ? "<span style='color: " + color + "'>" + word + '</span>' : item });
    new_words = words.join(' ');
    $('#' + text_id).html(new_words);
    }

Просто выберите элемент , содержащий текст, выбрав слово, которое нужно раскрасить, и выбранный цвет .

Вот пример :

<div id='my_words'>
This is some text to show that it is possible to color a specific word inside a body of text. The idea is to convert the text into an array using the split function, then iterate over each word until the word of interest is identified. Once found, the word of interest can be colored by replacing that element with a span around the word. Finally, replacing the text with jQuery's html() function will produce the desired result.
</div>

Использование ,

color_word('my_words', 'possible', 'hotpink')

введите описание изображения здесь


Вопрос содержит тег html, этот код удалит все теги html в результирующем div.
Муниб Мирза,

2

Вы можете использовать мой плагин выделения jQuiteLight , который также может работать с регулярными выражениями.

Для установки с использованием npm введите:

npm install jquitelight --save

Для установки с использованием типа bower :

bower install jquitelight 

Использование:

// for strings
$(".element").mark("query here");
// for RegExp
$(".element").mark(new RegExp(/query h[a-z]+/));

Более продвинутое использование здесь


@ user3631654 нет, это другой плагин. Мой плагин может работать с RegExp и имеет функцию умного выделения. Если вы включили плагин, который вы упомянули перед этим плагином, вы можете получить его с помощьюvar oldMark = $.fn.mark.noConflict()
iamawebgeek,

Похоже, что в jquery.mark есть метод markRegExp()для выделения пользовательских регулярных выражений. Так что это не должно быть аргументом.
user3631654

А @zazu, что значит "умная подсветка"?
user3631654

@ user3631654, если вы включите интеллектуальное выделение и передадите слово «следствие», оно также выделит слово «последствия» и другие его формы, но если вы передадите «the» или «bla», оно не будет принимать «тема» или «черный»
iamawebgeek,

2

JSFiddle

Пользы .each(), .replace(), .html(). Протестировано с jQuery 1.11 и 3.2.

В приведенном выше примере считывает «ключевое слово», которое нужно выделить, и добавляет тег 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;
}

1

Вам нужно получить содержимое тега p и заменить в нем все dolors на выделенную версию.

Для этого вам даже не нужен jQuery. :-)


9
Но с jQuery проще, не правда ли? ;)
Eikern

7
это можно сделать с помощью nokia 6310, для этого вам даже не нужен компьютер :-)
оклив

1

Я написал очень простую функцию, которая использует jQuery для итерации элементов, заключая каждое ключевое слово в класс .highlight.

function highlight_words(word, element) {
    if(word) {
        var textNodes;
        word = word.replace(/\W/g, '');
        var str = word.split(" ");
        $(str).each(function() {
            var term = this;
            var textNodes = $(element).contents().filter(function() { return this.nodeType === 3 });
            textNodes.each(function() {
              var content = $(this).text();
              var regex = new RegExp(term, "gi");
              content = content.replace(regex, '<span class="highlight">' + term + '</span>');
              $(this).replaceWith(content);
            });
        });
    }
}

Больше информации:

http://www.hawkee.com/snippet/9854/


2
Он не выполняет поиск во вложенных элементах, не имеет функции для удаления выделения и не имеет информации о лицензии.
чувак

Не могли бы вы объяснить мне, что такое «gi» в «новом RegExp (term,« gi »)»?
vuquanghoang

0

Я создал репозиторий по аналогичной концепции, который изменяет цвета текстов, цвета которых распознаются html5 (нам не нужно использовать фактические значения #rrggbb, и мы могли бы просто использовать имена как html5, стандартизированные около 140 из них)

colors.js colors.js

$( document ).ready(function() {
	
	function hiliter(word, element) {
		var rgxp = new RegExp("\\b" + word + "\\b" , 'gi'); // g modifier for global and i for case insensitive 
		var repl = '<span class="myClass">' + word + '</span>';
		element.innerHTML = element.innerHTML.replace(rgxp, repl);
			
			};

	hiliter('dolor', document.getElementById('dolor'));
});
.myClass{

background-color:red;
}
<!DOCTYPE html>
<html>
	<head>
		<title>highlight</title>
		
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
	
		 <link href="main.css" type="text/css"  rel="stylesheet"/>
		 
	</head>
	<body id='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>
 <script type="text/javascript" src="main.js" charset="utf-8"></script>
	</body>
</html>


-2

Возможно ли получить этот пример выше:

jQuery.fn.highlight = function (str, className)
{
    var regex = new RegExp(str, "g");

    return this.each(function ()
    {
        this.innerHTML = this.innerHTML.replace(
            regex,
            "<span class=\"" + className + "\">" + str + "</span>"
        );
    });
};

не заменять текст внутри html-тегов вроде, иначе страница ломается.


-2
$(function () {
    $("#txtSearch").keyup(function (event) {
        var txt = $("#txtSearch").val()
        if (txt.length > 3) {
            $("span.hilightable").each(function (i, v) {
                v.innerHTML = v.innerText.replace(txt, "<hilight>" + txt + "</hilight>");
            });

        }
    });
});

Jfiddle здесь


hilightне является допустимым элементом HTML
user3631654

Просто проигнорируйте это предупреждение, <hilight> - это ваш настраиваемый элемент, вы можете писать все, что хотите. Вы видели скрипку?
L.Grillo

@nickf, мой скрипт делает то же самое, что и принятый ответ
Л.Грилло,
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.