negrita mark example div javascript highlighting

javascript - example - mark js



Cómo resaltar texto usando javascript (12)

¿Alguien puede ayudarme con una función de JavaScript que puede resaltar texto en una página web? Y el requisito es: resaltar solo una vez, no resaltar todas las apariciones del texto como lo hacemos en el caso de la búsqueda.


¿Por qué usar una función de resaltado selfmade 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 el principio es porque seguramente encontrará problemas que otros ya han resuelto. Desafíos:

  • Tendría que eliminar los nodos de texto con elementos HTML para resaltar las coincidencias sin destruir los eventos DOM y desencadenar la regeneración de DOM una y otra vez (como sería el caso con 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 de resaltado busca coincidencias entre 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 haya pensado. ¡Y estoy hablando de pruebas de navegador cruzado!

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

Use un plugin existente

Al utilizar un complemento existente y bien implementado, no tiene que preocuparse por las cosas mencionadas anteriormente. Los complementos de jQuery text highlighter del artículo 10 en Sitepoint comparan los complementos populares de resaltado.

Eche un vistazo a mark.js

mark.js es un plugin que está escrito en JavaScript puro, pero también está disponible como plugin 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
  • usar elemento de resaltado personalizado
  • usar clase de resaltado personalizada
  • mapa de sinónimos personalizados
  • buscar también dentro de iframes
  • recibir términos no encontrados

DEMO

Alternativamente, puedes 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 un código abierto libre y desarrollado en GitHub ( referencia del proyecto ).


Ejemplo simple de TypeScript

NOTA: Si bien estoy de acuerdo con @Stefan en muchas cosas, solo necesitaba un simple resaltado de coincidencia:

module myApp.Search { ''use strict''; export class Utils { private static regexFlags = ''gi''; private static wrapper = ''mark''; private static wrap(match: string): string { return ''<'' + Utils.wrapper + ''>'' + match + ''</'' + Utils.wrapper + ''>''; } static highlightSearchTerm(term: string, searchResult: string): string { let regex = new RegExp(term, Utils.regexFlags); return searchResult.replace(regex, match => Utils.wrap(match)); } } }

Y luego construyendo el resultado real:

module myApp.Search { ''use strict''; export class SearchResult { id: string; title: string; constructor(result, term?: string) { this.id = result.id; this.title = term ? Utils.highlightSearchTerm(term, result.title) : result.title; } } }


Aquí está mi solución de JavaScript pura de regexp:

function highlight(text) { document.body.innerHTML = document.body.innerHTML.replace( new RegExp(text + ''(?!([^<]+)?<)'', ''gi''), ''<b style="background-color:#ff0;font-size:100%">$&</b>'' ); }


Desde HTML5, puede usar las <mark></mark> para resaltar el texto. Puede usar javascript para ajustar texto / palabra clave entre estas etiquetas. Aquí hay un pequeño ejemplo de cómo marcar y desmarcar el texto.

DEMO JSFIDDLE


Encontré el complemento highlight como la mejor opción, con él puedes resaltar parte del contenido :

$ (''li''). highlight (''bla'');


Las soluciones que se ofrecen aquí son bastante malas.

  1. No puede usar expresiones regulares, porque de esa manera, busca / resalta en las etiquetas html.
  2. No puede usar expresiones regulares, porque no funciona correctamente con UTF * (cualquier cosa con caracteres no latinos / ingleses).
  3. No se puede hacer un innerHTML.replace porque no funciona cuando los personajes tienen una notación HTML especial, por ejemplo &amp; para &, &lt; para <, &gt; para>, &auml; para ä, &ouml; para ö &uuml; para ü &szlig; para ß, etc.

Qué necesitas hacer:

Recorra el documento HTML, encuentre todos los nodos de texto, obtenga el contenido de textContent , obtenga la posición del texto indexOf con indexOf (con un valor opcional para toLowerCase si no distingue entre mayúsculas y minúsculas), agregue todo antes del indexof textNode , anexe el texto coincidente con un tramo resaltado, y repita para el resto del nodo de texto (la cadena resaltada puede aparecer varias veces en la cadena textContent ).

Aquí está el código para esto:

var InstantSearch = { "highlight": function (container, highlightText) { var internalHighlighter = function (options) { var id = { container: "container", tokens: "tokens", all: "all", token: "token", className: "className", sensitiveSearch: "sensitiveSearch" }, tokens = options[id.tokens], allClassName = options[id.all][id.className], allSensitiveSearch = options[id.all][id.sensitiveSearch]; function checkAndReplace(node, tokenArr, classNameAll, sensitiveSearchAll) { var nodeVal = node.nodeValue, parentNode = node.parentNode, i, j, curToken, myToken, myClassName, mySensitiveSearch, finalClassName, finalSensitiveSearch, foundIndex, begin, matched, end, textNode, span, isFirst; for (i = 0, j = tokenArr.length; i < j; i++) { curToken = tokenArr[i]; myToken = curToken[id.token]; myClassName = curToken[id.className]; mySensitiveSearch = curToken[id.sensitiveSearch]; finalClassName = (classNameAll ? myClassName + " " + classNameAll : myClassName); finalSensitiveSearch = (typeof sensitiveSearchAll !== "undefined" ? sensitiveSearchAll : mySensitiveSearch); isFirst = true; while (true) { if (finalSensitiveSearch) foundIndex = nodeVal.indexOf(myToken); else foundIndex = nodeVal.toLowerCase().indexOf(myToken.toLowerCase()); if (foundIndex < 0) { if (isFirst) break; if (nodeVal) { textNode = document.createTextNode(nodeVal); parentNode.insertBefore(textNode, node); } // End if (nodeVal) parentNode.removeChild(node); break; } // End if (foundIndex < 0) isFirst = false; begin = nodeVal.substring(0, foundIndex); matched = nodeVal.substr(foundIndex, myToken.length); if (begin) { textNode = document.createTextNode(begin); parentNode.insertBefore(textNode, node); } // End if (begin) span = document.createElement("span"); span.className += finalClassName; span.appendChild(document.createTextNode(matched)); parentNode.insertBefore(span, node); nodeVal = nodeVal.substring(foundIndex + myToken.length); } // Whend } // Next i }; // End Function checkAndReplace function iterator(p) { if (p === null) return; var children = Array.prototype.slice.call(p.childNodes), i, cur; if (children.length) { for (i = 0; i < children.length; i++) { cur = children[i]; if (cur.nodeType === 3) { checkAndReplace(cur, tokens, allClassName, allSensitiveSearch); } else if (cur.nodeType === 1) { iterator(cur); } } } }; // End Function iterator iterator(options[id.container]); } // End Function highlighter ; internalHighlighter( { container: container , all: { className: "highlighter" } , tokens: [ { token: highlightText , className: "highlight" , sensitiveSearch: false } ] } ); // End Call internalHighlighter } // End Function highlight };

Entonces puedes usarlo así:

function TestTextHighlighting(highlightText) { var container = document.getElementById("testDocument"); InstantSearch.highlight(container, highlightText); }

Aquí hay un documento HTML de ejemplo

<!DOCTYPE html> <html> <head> <title>Example of Text Highlight</title> <style type="text/css" media="screen"> .highlight{ background: #D3E18A;} .light{ background-color: yellow;} </style> </head> <body> <div id="testDocument"> This is a test <span> This is another test</span> äöüÄÖÜäöüÄÖÜ <span>Test123&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</span> </div> </body> </html>

Por cierto, si buscas en una base de datos con LIKE ,
ej. WHERE textField LIKE CONCAT(''%'', @query, ''%'') [que no deberías hacer, debes usar fulltext-search o Lucene], entonces puedes escapar cada carácter con / y agregar un SQL-escape- declaración, que si encuentra caracteres especiales que son expresiones LIKE.

p.ej

WHERE textField LIKE CONCAT(''%'', @query, ''%'') ESCAPE ''/'

y el valor de @query no es ''% completed'' sino ''/%/ /c/o/m/p/l/e/t/e/d''

(probado, funciona con SQL-Server y PostgreSQL, y cualquier otro sistema RDBMS que sea compatible con ESCAPE)


Me preguntaba que también podrías probar lo que aprendí en this publicación.

Solía:

function highlightSelection() { var userSelection = window.getSelection(); for(var i = 0; i < userSelection.rangeCount; i++) { highlightRange(userSelection.getRangeAt(i)); } } function highlightRange(range) { var newNode = document.createElement("span"); newNode.setAttribute( "style", "background-color: yellow; display: inline;" ); range.surroundContents(newNode); }

<html> <body contextmenu="mymenu"> <menu type="context" id="mymenu"> <menuitem label="Highlight Yellow" onclick="highlightSelection()" icon="/images/comment_icon.gif"></menuitem> </menu> <p>this is text, select and right click to high light me! if you can`t see the option, please use this<button onclick="highlightSelection()">button </button><p>

También puedes intentarlo aquí: http://henriquedonati.com/projects/Extension/extension.html

xc


Ninguna de las otras soluciones realmente se ajusta a mis necesidades, y aunque la solución de Stefan Steiger funcionó como esperaba, la encontré un poco demasiado detallada.

Lo siguiente es mi intento:

/** * Highlight keywords inside a DOM element * @param {string} elem Element to search for keywords in * @param {string[]} keywords Keywords to highlight * @param {boolean} caseSensitive Differenciate between capital and lowercase letters * @param {string} cls Class to apply to the highlighted keyword */ function highlight(elem, keywords, caseSensitive = false, cls = ''highlight'') { const flags = caseSensitive ? ''gi'' : ''g''; // Sort longer matches first to avoid // highlighting keywords within keywords. keywords.sort((a, b) => b.length - a.length); Array.from(elem.childNodes).forEach(child => { const keywordRegex = RegExp(keywords.join(''|''), flags); if (child.nodeType !== 3) { // not a text node highlight(child, keywords, caseSensitive, cls); } else if (keywordRegex.test(child.textContent)) { const frag = document.createDocumentFragment(); let lastIdx = 0; child.textContent.replace(keywordRegex, (match, idx) => { const part = document.createTextNode(child.textContent.slice(lastIdx, idx)); const highlighted = document.createElement(''span''); highlighted.textContent = match; highlighted.classList.add(cls); frag.appendChild(part); frag.appendChild(highlighted); lastIdx = idx + match.length; }); const end = document.createTextNode(child.textContent.slice(lastIdx)); frag.appendChild(end); child.parentNode.replaceChild(frag, child); } }); } // Highlight all keywords found in the page highlight(document.body, [''lorem'', ''amet'', ''autem'']);

.highlight { background: lightpink; }

<p>Hello world lorem ipsum dolor sit amet, consectetur adipisicing elit. Est vel accusantium totam, ipsum delectus et dignissimos mollitia!</p> <p> Lorem ipsum dolor sit amet, consectetur adipisicing elit. Numquam, corporis. <small>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Accusantium autem voluptas perferendis dolores ducimus velit error voluptatem, qui rerum modi?</small> </p>

También recomendaría usar algo como escape-string-regexp si tus palabras clave pueden tener caracteres especiales que deberían escaparse en expresiones regulares:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join(''|'')), flags);


Puede usar el efecto de resaltado jquery.

Pero si está interesado en el código javascript sin formato, eche un vistazo a lo que obtuve Simplemente copie y pegue en un HTML, abra el archivo y haga clic en "resaltar"; esto debería resaltar la palabra "zorro". En cuanto al rendimiento, creo que esto serviría para texto pequeño y una sola repetición (como usted especificó)

function highlight(text) { var inputText = document.getElementById("inputText"); var innerHTML = inputText.innerHTML; var index = innerHTML.indexOf(text); if (index >= 0) { innerHTML = innerHTML.substring(0,index) + "<span class=''highlight''>" + innerHTML.substring(index,index+text.length) + "</span>" + innerHTML.substring(index + text.length); inputText.innerHTML = innerHTML; } }

.highlight { background-color: yellow; }

<button onclick="highlight(''fox'')">Highlight</button> <div id="inputText"> The fox went over the fence </div>

Ediciones:

Usando replace

Veo que esta respuesta ganó algo de popularidad, pensé que podría agregar algo más. También puede usar fácilmente reemplazar

"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

O para múltiples ocurrencias (no relevante para la pregunta, pero se preguntó en comentarios) simplemente agrega global en la expresión regular de reemplazo.

"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

Espero que esto ayude a los comentaristas intrigados.

Reemplazar el HTML a toda la página web

para reemplazar el HTML de una página web completa, debe consultar innerHTML del cuerpo del documento.

document.body.innerHTML


Tengo el mismo problema, viene un montón de texto a través de una solicitud xmlhttp. Este texto tiene formato html. Necesito resaltar cada ocurrencia.

str=''<img src="brown fox.jpg" title="The brown fox" />'' +''<p>some text containing fox.</p>''

El problema es que no necesito resaltar el texto en las etiquetas. Por ejemplo, necesito destacar a Fox:

Ahora puedo reemplazarlo con:

var word="fox"; word="(//b"+ word.replace(/([{}()[/]//.?*+^$|=!:~-])/g, "//$1") + "//b)"; var r = new RegExp(word,"igm"); str.replace(r,"<span class=''hl''>$1</span>")

Para responder a su pregunta: puede omitir la g en las opciones de expresiones regulares y solo se reemplazará la primera aparición, pero esta sigue siendo la de la propiedad img src y destruye la etiqueta de la imagen:

<img src="brown <span class=''hl''>fox</span>.jpg" title="The brown <span class=''hl''>fox</span> />

Esta es la forma en que lo resolví, pero me preguntaba si hay una forma mejor, algo que me he perdido en las expresiones regulares:

str=''<img src="brown fox.jpg" title="The brown fox" />'' +''<p>some text containing 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>"); });


Usando el método surroundContents() en el tipo de Range . Su único argumento es un elemento que ajustará ese Rango.

function styleSelected() { bg = document.createElement("span"); bg.style.backgroundColor = "yellow"; window.getSelection().getRangeAt(0).surroundContents(bg); }


function stylizeHighlightedString() { var text = window.getSelection(); // For diagnostics var start = text.anchorOffset; var end = text.focusOffset - text.anchorOffset; range = window.getSelection().getRangeAt(0); var selectionContents = range.extractContents(); var span = document.createElement("span"); span.appendChild(selectionContents); span.style.backgroundColor = "yellow"; span.style.color = "black"; range.insertNode(span); }