Alguém pode me ajudar com uma função javascript que pode destacar o texto em uma página da web. E o requisito é - destacar apenas uma vez, não como destacar todas as ocorrências do texto como fazemos em caso de pesquisa.
Alguém pode me ajudar com uma função javascript que pode destacar o texto em uma página da web. E o requisito é - destacar apenas uma vez, não como destacar todas as ocorrências do texto como fazemos em caso de pesquisa.
Respostas:
Você pode usar o efeito de realce jquery .
Mas se você estiver interessado em código javascript bruto, dê uma olhada no que eu obtive. Simplesmente copie e cole em um HTML, abra o arquivo e clique em "destacar" - isso deve destacar a palavra "raposa". Em termos de desempenho, acho que isso seria suficiente para texto pequeno e uma única repetição (como você especificou)
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>
Editar% s:
replace
Vejo que essa resposta ganhou alguma popularidade, pensei em acrescentá-la. Você também pode usar facilmente substituir
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");
Ou para várias ocorrências (não relevantes para a pergunta, mas foram feitas nos comentários), basta adicionar global
a expressão regular de substituição.
"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");
Espero que isso ajude os comentaristas intrigados.
para substituir o HTML por uma página da web inteira, você deve consultar innerHTML
do corpo do documento.
document.body.innerHTML
"<span class='highlight'>"
por "<span style='color: " + color + ";'>"
, a cor deve ser algo comovar color = "#ff0000";
<img src="fox.jpg" />
Você obteria um HTML inválido que se pareceria com: <img src="<span class='highlight'>fox</span>.jpg" />
Não é bom
As soluções oferecidas aqui são muito ruins.
&
para &, <
para <, >
para>, ä
para ä, ö
para ö ü
para ü ß
para ß, etc.O que você precisa fazer:
Percorra o documento HTML, encontre todos os nós de texto, obtenha o textContent
, obtenha a posição do texto destacado com indexOf
(com um opcional toLowerCase
se não for sensível a maiúsculas e minúsculas), anexe tudo antes de indexof
como textNode
, anexe o texto correspondente com uma extensão de destaque, e repita para o resto do textnode (a string realçada pode ocorrer várias vezes na textContent
string).
Aqui está o código para isso:
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
};
Então você pode usá-lo assim:
function TestTextHighlighting(highlightText)
{
var container = document.getElementById("testDocument");
InstantSearch.highlight(container, highlightText);
}
Aqui está um exemplo de documento HTML
<!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>
A propósito, se você pesquisar em um banco de dados com LIKE
,
por exemplo WHERE textField LIKE CONCAT('%', @query, '%')
[o que você não deveria fazer, você deve usar fulltext-search ou Lucene], então você pode escapar de todos os caracteres com \ e adicionar uma instrução SQL-escape, dessa forma você encontrará caracteres especiais que são expressões LIKE.
por exemplo
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
e o valor de @query não é '%completed%'
senão'%\c\o\m\p\l\e\t\e\d%'
(testado, funciona com SQL-Server e PostgreSQL, e todos os outros sistemas RDBMS que suportam ESCAPE)
Uma versão datilografada 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 exemplo, será convertido para o caractere real, mesmo quando estiver usando innerHTML
.
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:
innerHTML
)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.
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.
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:
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 ).
acrossElements
opção. E para o terceiro comentário; mark.js não é grande em comparação com as funcionalidades que oferece. E não, é improvável que algo quebre no futuro, uma vez que mark.js foi testado, por exemplo, iniciando o Chrome 30 e em todas as versões mais novas com testes de unidade em vários navegadores e nunca houve problemas com as versões futuras.
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";
traduz em CSS style="background-color: yellow;"
- aquela diferença sutil entre o camelCase e a notação tracejada me atrapalhou no começo.
Esta é minha solução regexp de JavaScript puro:
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
>
caractere. Modifique o regex usando (?!([^<]+)?<)
para que funcione.
Eu tenho o mesmo problema, um monte de texto chega por meio de uma solicitação xmlhttp. Este texto está formatado em html. Eu preciso destacar cada ocorrência.
str='<img src="brown fox.jpg" title="The brown fox" />'
+'<p>some text containing fox.</p>'
O problema é que não preciso destacar o texto nas tags. Por exemplo, preciso destacar a raposa:
Agora posso substituí-lo por:
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 à sua pergunta: você pode deixar o g nas opções regexp e apenas a primeira ocorrência será substituída, mas esta ainda é a que está na propriedade img src e destrói a tag da imagem:
<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span
class='hl'>fox</span> />
Foi assim que resolvi, mas queria saber se existe uma maneira melhor, algo que perdi nas expressões 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">
ou <a href="word">
.
Nenhuma das outras soluções realmente atendeu às minhas necessidades e, embora a solução de Stefan Steiger tenha funcionado como eu esperava, achei-a um pouco prolixa.
A seguir está minha tentativa:
/**
* 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>
Eu também recomendaria usar algo como escape-string-regexp se suas palavras-chave puderem ter caracteres especiais que precisariam ser escapados em regexes:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
NOTA: Embora eu concorde com @Stefan em muitas coisas, eu só precisava de um simples destaque de correspondência:
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));
}
}
}
E então construir o 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 você pode usar o <mark></mark>
tags para destacar o texto. Você pode usar javascript para envolver algum texto / palavra-chave entre essas tags. Aqui está um pequeno exemplo de como marcar e desmarcar texto.
innerHTML
é perigoso. Isso excluirá eventos.
Avançando para 2019, a API da Web agora tem suporte nativo para destacar textos:
const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
E você está pronto para ir! anchorNode
é o nó inicial da seleção, focusNode
é o nó final da seleção. E, se forem nós de texto, offset
é o índice do caractere inicial e final nos respectivos nós. Aqui está a documentação
Eles até têm uma demonstração ao vivo
Eu também estava pensando nisso, você pode experimentar o que aprendi neste post.
Eu usei:
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>
você também pode tentar aqui: http://henriquedonati.com/projects/Extension/extension.html
xc
Se você também deseja que ele seja destacado no carregamento da página, há uma nova maneira.
apenas adicione #:~:text=Highlight%20These
tente acessar este link
/programming/38588721#:~:text=Highlight%20a%20text
Usando o método surroundContents () no tipo Range . Seu único argumento é um elemento que envolverá esse intervalo.
function styleSelected() {
bg = document.createElement("span");
bg.style.backgroundColor = "yellow";
window.getSelection().getRangeAt(0).surroundContents(bg);
}