¿Alguien puede ayudarme con una función de JavaScript que pueda 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 caso de búsqueda.
¿Alguien puede ayudarme con una función de JavaScript que pueda 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 caso de búsqueda.
Respuestas:
Puedes usar el efecto de resaltado de jquery .
Pero si está interesado en el código javascript sin procesar, 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 funcionarí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:
replace
Veo que esta respuesta ganó algo de popularidad, pensé que podría agregarla. También puede usar reemplazar fácilmente
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");
O para múltiples ocurrencias (no es relevante para la pregunta, pero se hizo en los comentarios) simplemente agregue global
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.
para reemplazar el HTML de una página web completa, debe consultar innerHTML
el cuerpo del documento.
document.body.innerHTML
"<span class='highlight'>"
con "<span style='color: " + color + ";'>"
, el color debería ser algo comovar color = "#ff0000";
<img src="fox.jpg" />
<img src="<span class='highlight'>fox</span>.jpg" />
Las soluciones que se ofrecen aquí son bastante malas.
&
para &, <
para <, >
para>, ä
para ä, ö
para ö ü
para ü ß
para ß, etc.Qué necesitas hacer:
Recorra el documento HTML, busque todos los nodos de texto, obtenga textContent
, obtenga la posición del texto resaltado con indexOf
(con un opcional toLowerCase
si no debe distinguir entre mayúsculas y minúsculas), agregue todo lo anterior indexof
como textNode
, agregue el texto coincidente con un intervalo resaltado, y repita para el resto del nodo de texto (la cadena resaltada puede ocurrir varias veces en eltextContent
cadena).
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äöüÄÖÜ</span>
</div>
</body>
</html>
Por cierto, si busca en una base de datos con LIKE
,
p . Ej.WHERE textField LIKE CONCAT('%', @query, '%')
[lo que no debe hacer, debe usar la búsqueda de texto completo o Lucene], entonces puede escapar de cada carácter con \ y agregar una declaración de escape SQL, de esa manera encontrará 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 admita ESCAPE)
Una versión mecanografiada revisada:
namespace SearchTools
{
export interface IToken
{
token: string;
className: string;
sensitiveSearch: boolean;
}
export class InstantSearch
{
protected m_container: Node;
protected m_defaultClassName: string;
protected m_defaultCaseSensitivity: boolean;
protected m_highlightTokens: IToken[];
constructor(container: Node, tokens: IToken[], defaultClassName?: string, defaultCaseSensitivity?: boolean)
{
this.iterator = this.iterator.bind(this);
this.checkAndReplace = this.checkAndReplace.bind(this);
this.highlight = this.highlight.bind(this);
this.highlightNode = this.highlightNode.bind(this);
this.m_container = container;
this.m_defaultClassName = defaultClassName || "highlight";
this.m_defaultCaseSensitivity = defaultCaseSensitivity || false;
this.m_highlightTokens = tokens || [{
token: "test",
className: this.m_defaultClassName,
sensitiveSearch: this.m_defaultCaseSensitivity
}];
}
protected checkAndReplace(node: Node)
{
let nodeVal: string = node.nodeValue;
let parentNode: Node = node.parentNode;
let textNode: Text = null;
for (let i = 0, j = this.m_highlightTokens.length; i < j; i++)
{
let curToken: IToken = this.m_highlightTokens[i];
let textToHighlight: string = curToken.token;
let highlightClassName: string = curToken.className || this.m_defaultClassName;
let caseSensitive: boolean = curToken.sensitiveSearch || this.m_defaultCaseSensitivity;
let isFirst: boolean = true;
while (true)
{
let foundIndex: number = caseSensitive ?
nodeVal.indexOf(textToHighlight)
: nodeVal.toLowerCase().indexOf(textToHighlight.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;
let begin: string = nodeVal.substring(0, foundIndex);
let matched: string = nodeVal.substr(foundIndex, textToHighlight.length);
if (begin)
{
textNode = document.createTextNode(begin);
parentNode.insertBefore(textNode, node);
} // End if (begin)
let span: HTMLSpanElement = document.createElement("span");
if (!span.classList.contains(highlightClassName))
span.classList.add(highlightClassName);
span.appendChild(document.createTextNode(matched));
parentNode.insertBefore(span, node);
nodeVal = nodeVal.substring(foundIndex + textToHighlight.length);
} // Whend
} // Next i
} // End Sub checkAndReplace
protected iterator(p: Node)
{
if (p == null)
return;
let children: Node[] = Array.prototype.slice.call(p.childNodes);
if (children.length)
{
for (let i = 0; i < children.length; i++)
{
let cur: Node = children[i];
// https://developer.mozilla.org/en-US/docs/Web/API/Node/nodeType
if (cur.nodeType === Node.TEXT_NODE)
{
this.checkAndReplace(cur);
}
else if (cur.nodeType === Node.ELEMENT_NODE)
{
this.iterator(cur);
}
} // Next i
} // End if (children.length)
} // End Sub iterator
public highlightNode(n:Node)
{
this.iterator(n);
} // End Sub highlight
public highlight()
{
this.iterator(this.m_container);
} // End Sub highlight
} // End Class InstantSearch
} // End Namespace SearchTools
Uso:
let searchText = document.getElementById("txtSearchText");
let searchContainer = document.body; // document.getElementById("someTable");
let highlighter = new SearchTools.InstantSearch(searchContainer, [
{
token: "this is the text to highlight" // searchText.value,
className: "highlight", // this is the individual highlight class
sensitiveSearch: false
}
]);
// highlighter.highlight(); // this would highlight in the entire table
// foreach tr - for each td2
highlighter.highlightNode(td2); // this highlights in the second column of table
ä
por ejemplo, se convertirá al carácter real, incluso cuando se utilice innerHTML
.
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:
innerHTML
)¿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.
Al utilizar un complemento existente y bien implementado, no tiene que preocuparse por las cosas mencionadas anteriormente. Los complementos de resaltador de texto de jQuery del artículo 10 en Sitepoint compara los complementos de resaltador populares.
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:
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 ).
acrossElements
opción. Y al tercer comentario; mark.js no es grande en comparación con las funcionalidades que ofrece. Y no, es poco probable que algo se rompa en el futuro, ya que mark.js se probó, por ejemplo, al iniciar Chrome 30 y en todas las versiones más nuevas con pruebas unitarias entre navegadores y nunca hubo problemas con las próximas versiones.
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);
}
span.style.backgroundColor = "yellow";
traduce en CSS: style="background-color: yellow;"
esa sutil diferencia entre camelCase y la notación discontinua me hizo tropezar al principio.
Aquí está mi solución de JavaScript puro regexp:
function highlight(text) {
document.body.innerHTML = document.body.innerHTML.replace(
new RegExp(text + '(?!([^<]+)?<)', 'gi'),
'<b style="background-color:#ff0;font-size:100%">$&</b>'
);
}
one|two|three
>
carácter. Modifique la expresión regular usando (?!([^<]+)?<)
para que funcione.
Tengo el mismo problema, entra 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 resaltar 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 manera 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>");
});
<img src="word">
o <a href="word">
.
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 que sigue 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 sus palabras clave pueden tener caracteres especiales que deberían escaparse en las expresiones regulares:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
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;
}
}
}
Desde HTML5 puede utilizar el <mark></mark>
etiquetas para resaltar texto. Puede usar javascript para envolver algún texto / palabra clave entre estas etiquetas. A continuación, se muestra un pequeño ejemplo de cómo marcar y desmarcar texto.
innerHTML
es peligroso. Eliminará eventos.
Avance rápido hasta 2019, Web API ahora tiene soporte nativo para resaltar textos:
const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
¡Y estás listo! anchorNode
es el nodo inicial de la selección, focusNode
es el nodo final de la selección. Y, si son nodos de texto, offset
es el índice del carácter inicial y final en los nodos respectivos. Aquí está la documentación
Incluso tienen una demostración en vivo
También me preguntaba eso, podrías probar lo que aprendí sobre esto. 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 probarlo aquí: http://henriquedonati.com/projects/Extension/extension.html
xc
Si también desea que se destaque en la carga de la página, hay una nueva forma.
solo agrega #:~:text=Highlight%20These
intente acceder a este enlace
/programming/38588721#:~:text=Highlight%20a%20text
Usando el método surroundContents () en el tipo de rango . Su único argumento es un elemento que envolverá ese rango.
function styleSelected() {
bg = document.createElement("span");
bg.style.backgroundColor = "yellow";
window.getSelection().getRangeAt(0).surroundContents(bg);
}