Resalta una palabra con jQuery

101

Básicamente, necesito resaltar una palabra en particular en un bloque de texto. Por ejemplo, imagina que quiero resaltar la palabra "dolor" en este 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>

¿Cómo convierto lo anterior en algo como esto?

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

¿Es esto posible con jQuery?

Editar : como señaló Sebastian , esto es bastante posible sin jQuery, pero esperaba que hubiera un método especial de jQuery que le permitiera hacer selectores en el texto en sí. Ya estoy usando jQuery en gran medida en este sitio, por lo que mantener todo envuelto en jQuery haría las cosas quizás un poco más ordenadas.

nickf
fuente
Esto también puede ser de interés: jquery.info/The-plugin-SearchHighlight
Eikern
Oye, escribí un complemento que hace exactamente esto: es como el complemento de Johann Burkard publicado por mlarsen, pero funciona con expresiones regulares en lugar de cadenas. Compruébelo en github y avíseme si hay funciones adicionales que necesita.
3
En caso de que necesite una versión indulgente del complemento de resaltado de jQuery: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör
1
En lugar de resaltar las palabras con a <span>, es más correcto usarlo <mark>, hablando semánticamente.
Jose Rui Santos
Hola, llegué tarde, pero aquí hay otro fragmento de código que ayuda a resaltar y filtrar el texto según las etiquetas. Con suerte, eso ayudará a alguien jQuery Plugin para resaltar y
filtrar

Respuestas:

85

Intente resaltar: texto de JavaScript que resalta el complemento jQuery .! Advertencia: el código fuente disponible en esta página contiene un script de minería de criptomonedas, use el código a continuación o elimine el script de minería de la descarga en el sitio web. !

/*

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

Pruebe también la versión "actualizada" del 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
fuente
Hay dos soluciones y están contenidas en un archivo cada una. Los agregué arriba. Al menos, en el peor de los casos, siempre estarán disponibles aquí en el historial de edición.
Erick Robertson
resaltar v4 tiene un poco de errores. Hay una solución en la página de inicio de Burkard: johannburkard.de/blog/programming/javascript/… En este caso, no fue una buena idea copiar el código aquí; el enlace apunta a la última versión (ahora :)).
Lerin Sonberg
Por cierto, la etiqueta <mark> es probablemente mejor que la etiqueta <span> aquí.
unitario
1
Si está buscando algo pequeño y liviano, el complemento jquery destacado es de hecho su mejor opción. Es excelente para resaltar y eliminar resaltados que coinciden con el texto dado. Si necesita expresión regular u otro apoyo; sin embargo, echa un vistazo a mark.js o cualquiera de las extensiones y bifurcaciones para resaltar vinculado desde la página de resaltado. Yo uso resaltarme a mí mismo sobre otros porque el peso ligero es muy apreciado.
Greg
3
IMPORTANTE: ¡¡¡¡Johann Burkard incluyó un script de minería en la fuente proporcionada en su sitio web !!!!!!
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
fuente
2
No desea utilizar innerHTML, ya que Microsoft lo introdujo en los años 80 y luego lo abandonó Microsoft nuevamente, como de costumbre. Aunque la mayoría de los navegadores lo admiten, es todo menos el estándar W3C.
Steve K
21
¿Qué debería usar en lugar de innerHTML?
Kebman
15
@Sir Ben Benji: Creo que está confundiendo innerHTML con innerText (la alternativa desarrollada por Microsoft a textContent, que de hecho es un anatema para las especificaciones). innerHTML puede haber comenzado como una extensión de Microsoft, pero de ninguna manera se ha "eliminado"; ha sido compatible con todos los navegadores principales desde principios de la década de 2000 y es parte de HTML5 (ya en 2008): w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml Todavía está presente en la última versión revisión en w3.org/TR/DOM-Parsing . Véase también w3.org/TR/html5/references.html#refsDOMPARSING
Jay Dansand
1
No es una buena solución. Acabo de usar esto, pero si busco, por ejemplo, 'persona', también reemplaza todas las clases y elementos html con 'persona' en él. Y las minúsculas y las mayúsculas tampoco están integradas. var rgxp = new RegExp ("(\\ b" + palabra + "\\ b)", "gim"); arregló eso, pero aún así, creo que el código no debería reemplazar los elementos html.
Richard Lindhout
32

Por qué usar una función de resaltado hecha por uno mismo es una mala idea

La razón por la que probablemente sea una mala idea comenzar a construir su propia función de resaltado desde cero es porque seguramente se encontrará con problemas que otros ya han resuelto. Desafíos:

  • Debería eliminar los nodos de texto con elementos HTML para resaltar sus coincidencias sin destruir los eventos DOM y desencadenar la regeneración DOM una y otra vez (que sería el caso, por ejemplo innerHTML)
  • Si desea eliminar los elementos resaltados, deberá eliminar los elementos HTML con su contenido y también deberá combinar los nodos de texto divididos para realizar más búsquedas. Esto es necesario porque cada complemento resaltador busca coincidencias dentro de los nodos de texto y, si sus palabras clave se dividirán en varios nodos de texto, no se encontrarán.
  • También necesitaría crear pruebas para asegurarse de que su complemento funcione en situaciones en las que no ha pensado. ¡Y estoy hablando de pruebas entre navegadores!

¿Suena complicado? Si desea algunas funciones como ignorar algunos elementos de resaltado, mapeo de diacríticos, mapeo de sinónimos, búsqueda dentro de iframes, búsqueda de palabras separadas, etc., esto se vuelve cada vez más complicado.

Usar un complemento existente

Al utilizar un complemento existente y bien implementado, no tiene que preocuparse por las cosas mencionadas anteriormente. El artículo 10 complementos de resaltador de texto de jQuery en Sitepoint compara los complementos de resaltador populares. Esto incluye complementos de respuestas a esta pregunta.

Eche un vistazo a mark.js

mark.js es un complemento escrito en JavaScript puro, pero también está disponible como complemento jQuery. Fue desarrollado para ofrecer más oportunidades que los otros complementos con opciones para:

  • buscar palabras clave por separado en lugar del término completo
  • diacríticos del mapa (por ejemplo, si "justo" también debe coincidir con "justò")
  • ignorar coincidencias dentro de elementos personalizados
  • utilizar elemento de resaltado personalizado
  • usar clase de resaltado personalizada
  • sinónimos personalizados de mapas
  • buscar también dentro de iframes
  • recibir términos no encontrados

MANIFESTACIÓN

Alternativamente, puede ver este violín .

Ejemplo de uso :

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

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

Es gratis y está desarrollado de código abierto en GitHub ( referencia del proyecto ).

tipo
fuente
11

Aquí hay una variación que ignora y conserva el caso:

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
fuente
6
Esto funciona para texto sin formato, pero no parece excluir etiquetas y atributos. es decir, busque "lass" cuando tenga un atributo de clase en un div en su innerHTML.
Jonathan
¿Cómo se invoca esta función?
Jiy
innerHTMLes malvado, mira mi respuesta aquí. Además, \\bno funciona con caracteres Unicode. Además, esta función omite casi todo, por ejemplo, buscar dentro de los niños anidados.
amigo
3

Puede utilizar la siguiente función para resaltar cualquier palabra en su 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);
    }

Simplemente apunte al elemento que contiene el texto, eligiendo la palabra a colorear y el color de su elección.

He aquí un ejemplo :

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

el uso ,

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

ingrese la descripción de la imagen aquí

Azle también tiene una buena función para esto. Utiliza clases, así que simplemente asigne un nombre de clase a cualquier bloque de texto que desee apuntar.

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

Puede usar mi complemento de resaltado jQuiteLight , que también puede funcionar con expresiones regulares.

Para instalar usando el tipo npm :

npm install jquitelight --save

Para instalar usando el tipo de bower :

bower install jquitelight 

Uso:

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

Uso más avanzado aquí

iamawebgeek
fuente
@ user3631654 no, ese es un complemento diferente. Mi complemento puede funcionar con RegExp y tiene una función de resaltado inteligente. Si ha incluido el complemento que ha mencionado antes de este complemento, puede obtenerlo usandovar oldMark = $.fn.mark.noConflict()
iamawebgeek
Parece que jquery.mark tiene un método markRegExp()para resaltar también expresiones regulares personalizadas. Entonces esto no debería ser un argumento.
user3631654
Y @zazu, ¿qué quieres decir con "resaltado inteligente"?
user3631654
@ user3631654 si activa el resaltado inteligente y pasa una palabra "consequnce", también resaltará la palabra "consecuencias" y sus otras formas, pero si pasa "el" o "bla" no tomará "tema" o "negro"
iamawebgeek
2

JSFiddle

Utiliza .each (), .replace (), .html (). Probado con jQuery 1.11 y 3.2.

En el ejemplo anterior, lee la 'palabra clave' para resaltarla y agrega la etiqueta span con la clase 'resaltar'. El texto 'palabra clave' se resalta para todas las clases seleccionadas en .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
fuente
1

Necesita obtener el contenido de la etiqueta p y reemplazar todos los dolors con la versión resaltada.

Ni siquiera necesitas tener jQuery para esto. :-)

Sebastián Hoitz
fuente
9
Pero es más fácil con jQuery, ¿no? ;)
Eikern
7
se puede hacer con nokia 6310, ni siquiera necesita tener una PC para esto :-)
okliv
1

Escribí una función muy simple que usa jQuery para iterar los elementos que envuelven cada palabra clave con una clase .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);
            });
        });
    }
}

Más información:

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

Hawkee
fuente
2
Esto no busca en elementos anidados, no tiene función para eliminar resaltados y no tiene información de licencia.
dude
¿Te importaría explicarme qué es 'gi' en "nueva RegExp (término," gi ")"?
vuquanghoang
0

He creado un repositorio con un concepto similar que cambia los colores de los textos cuyos colores son reconocidos por html5 (no tenemos que usar valores #rrggbb reales y podríamos usar los nombres como html5 estandarizado alrededor de 140 de ellos)

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

¿Es posible obtener este ejemplo anterior?

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

no reemplazar el texto dentro de las etiquetas html como, de lo contrario, esto rompe la página.

nickf
fuente
-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 aquí

L.Grillo
fuente
hilightno es un elemento HTML válido
user3631654
Simplemente ignore esta advertencia, <hilight> es su elemento personalizado, puede escribir lo que quiera. ¿Has visto el violín?
L.Grillo
@nickf mi guión hace exactamente lo mismo que la respuesta aceptada
L.Grillo