Qualcuno può aiutarmi con una funzione javascript in grado di evidenziare il testo su una pagina web. E il requisito è di - evidenziare solo una volta, non come evidenziare tutte le occorrenze del testo come facciamo in caso di ricerca.
Qualcuno può aiutarmi con una funzione javascript in grado di evidenziare il testo su una pagina web. E il requisito è di - evidenziare solo una volta, non come evidenziare tutte le occorrenze del testo come facciamo in caso di ricerca.
Risposte:
Puoi usare l' effetto di evidenziazione jquery .
Ma se sei interessato al codice javascript grezzo, dai un'occhiata a quello che ho ottenuto. Copia semplicemente incolla in un HTML, apri il file e fai clic su "evidenzia" - questo dovrebbe evidenziare la parola "volpe". Per quanto riguarda le prestazioni, penso che questo andrebbe bene per un testo piccolo e una singola ripetizione (come hai specificato)
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>
Modifiche:
replace
Vedo che questa risposta ha guadagnato una certa popolarità, ho pensato di aggiungerla. Puoi anche usare facilmente sostituisci
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");
O per più occorrenze (non rilevanti per la domanda, ma è stato chiesto nei commenti) aggiungi semplicemente global
l'espressione regolare di sostituzione.
"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");
Spero che questo aiuti i commentatori incuriositi.
per sostituire l'HTML per un'intera pagina web, dovresti fare riferimento al innerHTML
corpo del documento.
document.body.innerHTML
"<span class='highlight'>"
con "<span style='color: " + color + ";'>"
, il colore dovrebbe essere qualcosa del tipovar color = "#ff0000";
<img src="fox.jpg" />
Si otterrebbe un codice HTML non valido che sarebbe: <img src="<span class='highlight'>fox</span>.jpg" />
Non buono
Le soluzioni offerte qui sono piuttosto scadenti.
&
per &, <
per <, >
per>, ä
per ä, ö
per ö ü
per ü ß
per ß, ecc.Cosa devi fare:
Passa attraverso il documento HTML, trova tutti i nodi di testo, ottieni il textContent
, ottieni la posizione del testo evidenziato con indexOf
(con un opzionale toLowerCase
se dovrebbe essere senza distinzione tra maiuscole e minuscole), aggiungi tutto prima indexof
come textNode
, aggiungi il testo corrispondente con un intervallo di evidenziazione, e ripeti per il resto del textnode (la stringa di evidenziazione potrebbe ricorrere più volte nella textContent
stringa).
Ecco il codice per questo:
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
};
Quindi puoi usarlo in questo modo:
function TestTextHighlighting(highlightText)
{
var container = document.getElementById("testDocument");
InstantSearch.highlight(container, highlightText);
}
Ecco un esempio di 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 proposito, se cerchi in un database con LIKE
,
ad es. WHERE textField LIKE CONCAT('%', @query, '%')
[ Cosa che non dovresti fare, dovresti usare la ricerca full-text o Lucene], puoi fare l'escape di ogni carattere con \ e aggiungere un'istruzione SQL-escape, in questo modo troverai caratteri speciali che sono espressioni LIKE.
per esempio
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
e il valore di @query non è '%completed%'
ma'%\c\o\m\p\l\e\t\e\d%'
(testato, funziona con SQL-Server e PostgreSQL e ogni altro sistema RDBMS che supporta ESCAPE)
Una versione modificata del dattiloscritto:
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
Utilizzo:
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
ä
ad esempio, verrà convertito nel carattere effettivo, anche quando si utilizza innerHTML
.
Il motivo per cui è probabilmente una cattiva idea iniziare a costruire la tua funzione di evidenziazione da zero è perché sicuramente ti imbatterai in problemi che altri hanno già risolto. Sfide:
innerHTML
)Sembra complicato? Se desideri alcune funzionalità come ignorare alcuni elementi dall'evidenziazione, la mappatura dei segni diacritici, la mappatura dei sinonimi, la ricerca all'interno di iframe, la ricerca di parole separate, ecc., Questo diventa sempre più complicato.
Quando usi un plugin esistente e ben implementato, non devi preoccuparti delle cose sopra nominate. L'articolo 10 plugin per evidenziatori di testo jQuery su Sitepoint a confronto i plugin per evidenziatori più diffusi.
mark.js è un plug-in di questo tipo scritto in JavaScript puro, ma è anche disponibile come plug-in jQuery. È stato sviluppato per offrire più opportunità rispetto agli altri plugin con opzioni per:
In alternativa puoi vedere questo violino .
Esempio di utilizzo :
// Highlight "keyword" in the specified context
$(".context").mark("keyword");
// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);
È gratuito e sviluppato open-source su GitHub ( riferimento del progetto ).
acrossElements
opzione. E al terzo commento; mark.js non è grande rispetto alle funzionalità che offre. E no, è improbabile che qualcosa si rompa in futuro, dal momento che mark.js è stato testato ad esempio avviando Chrome 30 e in tutte le versioni più recenti con unit test cross-browser e non ci sono mai stati problemi con le versioni imminenti.
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 in CSS: quella style="background-color: yellow;"
sottile differenza tra camelCase e notazione tratteggiata mi ha fatto scattare all'inizio.
Ecco la mia soluzione JavaScript pura di 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
>
carattere. Modifica la regex usando (?!([^<]+)?<)
per farla funzionare.
Ho lo stesso problema, un mucchio di testo arriva tramite una richiesta xmlhttp. Questo testo è in formato html. Devo evidenziare ogni evento.
str='<img src="brown fox.jpg" title="The brown fox" />'
+'<p>some text containing fox.</p>'
Il problema è che non ho bisogno di evidenziare il testo nei tag. Ad esempio, devo evidenziare la volpe:
Ora posso sostituirlo 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>")
Per rispondere alla tua domanda: puoi lasciare fuori la g nelle opzioni regexp e solo la prima occorrenza verrà sostituita, ma questa è ancora quella nella proprietà img src e distrugge il tag immagine:
<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span
class='hl'>fox</span> />
Questo è il modo in cui l'ho risolto, ma mi chiedevo se esiste un modo migliore, qualcosa che mi è sfuggito nelle espressioni regolari:
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">
.
Nessuna delle altre soluzioni si adattava davvero alle mie esigenze e, sebbene la soluzione di Stefan Steiger abbia funzionato come mi aspettavo, l'ho trovata un po 'troppo prolissa.
Di seguito è il mio tentativo:
/**
* 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>
Consiglierei anche di usare qualcosa di simile escape-string-regexp se le tue parole chiave possono avere caratteri speciali che dovrebbero essere sottoposti a escape nelle espressioni regolari:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
NOTA: anche se sono d'accordo con @Stefan in molte cose, avevo solo bisogno di una semplice evidenziazione della corrispondenza:
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 poi costruendo il risultato effettivo:
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;
}
}
}
Dal momento che HTML5 puoi usare i <mark></mark>
tag per evidenziare il testo. Puoi usare javascript per racchiudere del testo / parola chiave tra questi tag. Ecco un piccolo esempio di come contrassegnare e deselezionare il testo.
innerHTML
è pericoloso. Eliminerà gli eventi.
Avanti veloce al 2019, l'API Web ora ha il supporto nativo per evidenziare i testi:
const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
E sei a posto! anchorNode
è il nodo iniziale della selezione, focusNode
è il nodo finale della selezione. E, se sono nodi di testo, offset
è l'indice del carattere iniziale e finale nei rispettivi nodi. Ecco la documentazione
Hanno anche una demo dal vivo
Mi stavo chiedendo anche questo, potresti provare quello che ho imparato in questo post.
Ero solito:
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>
potresti provarlo anche qui: http://henriquedonati.com/projects/Extension/extension.html
xc
Noi, se vuoi che venga evidenziato anche al caricamento della pagina, c'è un nuovo modo.
basta aggiungere #:~:text=Highlight%20These
prova ad accedere a questo link
/programming/38588721#:~:text=Highlight%20a%20text
Usando il metodo surroundContents () sul tipo Range . Il suo unico argomento è un elemento che avvolgerà quell'intervallo.
function styleSelected() {
bg = document.createElement("span");
bg.style.backgroundColor = "yellow";
window.getSelection().getRangeAt(0).surroundContents(bg);
}