Destaque uma palavra com jQuery

101

Basicamente, preciso destacar uma palavra específica em um bloco de texto. Por exemplo, finja que eu queria destacar a palavra "dolor" neste texto:

<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>

Como faço para converter o código acima em algo assim:

<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>

Isso é possível com jQuery?

Edit : Como Sebastian apontou , isso é perfeitamente possível sem jQuery - mas eu esperava que pudesse haver um método especial de jQuery que permitiria fazer seletores no próprio texto. Já estou usando jQuery intensamente neste site, então manter tudo embrulhado em jQuery tornaria as coisas talvez um pouco mais organizadas.

nickf
fonte
Isso também pode ser de interesse: jquery.info/The-plugin-SearchHighlight
Eikern
Ei, eu escrevi um plugin que faz exatamente isso - é como o plugin de Johann Burkard postado por mlarsen, mas funciona com expressões regulares em vez de strings. Verifique no github e por favor me diga se há recursos adicionais de que você precisa.
3
Caso você precise de uma versão branda do plugin jQuery realce: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör
1
Em vez de destacar palavras com um <span>, é mais correto usar <mark>semanticamente falando.
José Rui Santos
Olá, estou a bordo atrasado, mas aqui está outro trecho de código que ajuda a destacar e filtrar o texto com base em tags. Esperançosamente, isso ajudará alguém Plugin jQuery para realce e filtragem de texto
Jaspreet Chahal

Respostas:

85

Tente destaque: texto JavaScript destacando o plugin jQuery .! Aviso - O código-fonte disponível nesta página contém um script de mineração de moeda criptográfica, use o código abaixo ou remova o script de mineração do download no site. !

/*

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:[email protected]>

*/

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

Experimente também a versão "atualizada" do script original .

/*
 * 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);
    });
};
mlarsen
fonte
Existem duas soluções, e elas estão contidas em um arquivo cada. Eu os adicionei acima. Pelo menos, na pior das hipóteses, eles sempre estarão disponíveis aqui no histórico de edições.
Erick Robertson,
o destaque v4 tem alguns bugs. Há uma correção na página inicial de Burkard: johannburkard.de/blog/programming/javascript/… Nesse caso, não foi uma boa ideia copiar o código aqui; o link aponta para a versão mais recente (agora :)).
Lerin Sonberg
A propósito, a tag <mark> é provavelmente melhor do que a tag <span> aqui.
unitario
1
Se você está procurando por algo pequeno e leve, o plugin realce jquery é de fato sua melhor escolha. É ótimo para destacar e remover destaques que correspondem ao texto fornecido. Se você precisar de expressão regular ou outro suporte; no entanto, verifique mark.js ou qualquer uma das extensões e garfos para destaque vinculado a partir da página de destaque. Eu uso me destacar sobre os outros porque o peso leve é ​​muito apreciado.
Greg
3
IMPORTANTE: Johann Burkard incluiu um script de mineração na fonte fornecida em seu site !!!!!!
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');
Andrew Hedges
fonte
2
Você não quer usar o innerHTML como foi introduzido pela Microsoft nos anos 80 e posteriormente abandonado pela Microsoft novamente, como de costume. Embora a maioria dos navegadores o suporte, é tudo menos o padrão do W3C.
Steve K
21
O que você deve usar em vez de innerHTML?
Kebman
15
@Sir Ben Benji: Acho que você está confundindo innerHTML com innerText (a alternativa desenvolvida pela Microsoft para textContent, que é de fato um anátema para as especificações). innerHTML pode ter começado como uma extensão da Microsoft, mas de forma alguma foi "descartado"; é suportado por todos os principais navegadores desde o início dos anos 2000 e faz parte do HTML5 (já em 2008): w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml Ainda está presente no último revisão em w3.org/TR/DOM-Parsing . Consulte também w3.org/TR/html5/references.html#refsDOMPARSING
Jay Dans e
1
Não é uma solução muito boa. Acabei de usar isso, mas se eu pesquisar por exemplo 'pessoa', também substitui todas as classes e elementos html por 'pessoa' nele. E minúsculas e maiúsculas também não são integradas. var rgxp = new RegExp ("(\\ b" + palavra + "\\ b)", "gim"); consertou isso, mas ainda assim, acho que o código não deve substituir os elementos html.
Richard Lindhout
32

Por que usar uma função de realce criada por você mesmo é uma má ideia

O motivo pelo qual provavelmente é uma má ideia começar a construir sua própria função de realce do zero é porque você certamente encontrará problemas que outros já resolveram. Desafios:

  • Você precisaria remover nós de texto com elementos HTML para destacar suas correspondências sem destruir eventos DOM e acionar a regeneração DOM repetidamente (o que seria o caso com, por exemplo innerHTML)
  • Se você quiser remover os elementos destacados, terá que remover os elementos HTML com seu conteúdo e também combinar os nós de texto divididos para pesquisas futuras. Isso é necessário porque cada plug-in de marca-texto procura correspondências dentro de nós de texto e se suas palavras-chave forem divididas em vários nós de texto, elas não serão encontradas.
  • Você também precisaria construir testes para certificar-se de que seu plugin funcione em situações nas quais você não pensou. E estou falando sobre testes entre navegadores!

Parece complicado? Se você deseja alguns recursos como ignorar alguns elementos de realce, mapeamento de diacríticos, mapeamento de sinônimos, pesquisa dentro de iframes, pesquisa de palavras separadas, etc., isso se torna cada vez mais complicado.

Use um plugin existente

Ao usar um plugin existente e bem implementado, você não precisa se preocupar com as coisas nomeadas acima. O artigo 10 dos plug - ins de realce de texto da jQuery no Sitepoint compara os plug-ins de realce populares. Isso inclui plug-ins de respostas a esta pergunta.

Dê uma olhada em mark.js

mark.js é um plugin escrito em JavaScript puro, mas também está disponível como plugin jQuery. Ele foi desenvolvido para oferecer mais oportunidades do que os outros plug-ins com opções para:

  • pesquise palavras-chave separadamente em vez do termo completo
  • diacríticos do mapa (por exemplo, se "justo" também deve corresponder a "justò")
  • ignorar correspondências dentro de elementos personalizados
  • usar elemento de destaque personalizado
  • usar classe de destaque personalizada
  • sinônimos personalizados de mapas
  • pesquise também dentro de iframes
  • receber termos não encontrados

DEMO

Alternativamente, você pode ver este violino .

Exemplo de uso :

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

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

É gratuito e desenvolvido em código aberto no GitHub ( referência do projeto ).

cara
fonte
11

Aqui está uma variação que ignora e preserva maiúsculas e minúsculas:

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>";});
    });
};
bjarlestam
fonte
6
Isso funciona para texto simples, mas não parece excluir tags e atributos. isto é, procure por "lass" quando você tiver um atributo de classe em um div em seu innerHTML.
Jonathan,
Como essa função é chamada?
julho
innerHTMLé mau, veja minha resposta aqui. Além disso, \\bnão funciona para caracteres Unicode. Além disso, essa função perde quase tudo, por exemplo, pesquisar dentro de filhos aninhados.
cara
3

Você pode usar a seguinte função para destacar qualquer palavra em seu texto.

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

Basta direcionar o elemento que contém o texto, escolhendo a palavra para colorir e a cor de escolha.

Aqui está um exemplo :

<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>

Uso ,

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

insira a descrição da imagem aqui

O Azle também tem uma função legal para isso. Ele usa classes, então apenas atribua um nome de classe a qualquer bloco de texto que você deseja direcionar.

az.style_word("target_class", target_instance, {
     "this_class" : "pink_word",
     "word" : "possible", // list any CSS styling after this line ...
     "color" : "hotpink", 
     "font-weight" : "bold"
})
Cibernético
fonte
2

Você pode usar meu plugin de destaque jQuiteLight , que também pode funcionar com expressões regulares.

Para instalar usando o tipo npm :

npm install jquitelight --save

Para instalar usando o tipo de caramanchão :

bower install jquitelight 

Uso:

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

Uso mais avançado aqui

iamawebgeek
fonte
@ user3631654 não, é um plugin diferente. Meu plugin pode funcionar com RegExp e tem um recurso de destaque inteligente. Se você incluiu o plugin que você mencionou antes, você pode obtê-lo usandovar oldMark = $.fn.mark.noConflict()
iamawebgeek
Parece que jquery.mark tem um método markRegExp()para destacar também expressões regulares personalizadas. Portanto, isso não deve ser um argumento.
user3631654
E @zazu, o que você quer dizer com "destaque inteligente"?
user3631654
@ user3631654 se você ativar o destaque inteligente e passar a palavra "conseqüência", ele também destacará a palavra "consequências" e suas outras formas, mas se você passar "o" ou "bla", não será "tema" ou "preto"
iamawebgeek
2

JSFiddle

Usa .each (), .replace (), .html (). Testado com jQuery 1.11 e 3.2.

No exemplo acima, lê a 'palavra-chave' a ser destacada e acrescenta a tag span com a classe 'destaque'. O texto 'palavra-chave' é destacado para todas as classes selecionadas em .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;
}
Van Peer
fonte
1

Você precisa obter o conteúdo da tag p e substituir todos os dolors nela pela versão destacada.

Você nem precisa ter o jQuery para isso. :-)

Sebastian Hoitz
fonte
9
Mas é mais fácil com jQuery, não é? ;)
Eikern
7
pode ser feito com o nokia 6310, você nem precisa ter PC para isso :-)
okliv 20/10/2014
1

Eu escrevi uma função muito simples que usa jQuery para iterar os elementos que envolvem cada palavra-chave com uma classe .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);
            });
        });
    }
}

Mais informações:

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

Hawkee
fonte
2
Isso não pesquisa em elementos aninhados, não tem função para remover realces e não tem informações de licença.
cara
Importa-se de me explicar o que é 'gi' em "new RegExp (termo," gi ")"?
vuquanghoang
0

Eu criei um repositório com um conceito semelhante que muda as cores dos textos cujas cores são reconhecidas por html5 (não temos que usar valores #rrggbb reais e poderíamos apenas usar os nomes como html5 padronizados em cerca de 140 deles)

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>

abe312
fonte
-2

É possível obter este exemplo acima:

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

não substituir o texto dentro de tags html como, caso contrário, quebra a página.

nickf
fonte
-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 aqui

L.Grillo
fonte
hilightnão é um elemento HTML válido
user3631654
Apenas ignore este aviso, <hilight> é o seu elemento personalizado, você pode escrever o que quiser. Você viu o violino?
L.Grillo
@nickf meu script faz exatamente a mesma coisa da resposta aceita
L.Grillo