Come evidenziare il testo usando javascript


98

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.


4
Se pubblichi il codice della funzione saremo in grado di aiutarti. Se ci chiedi di creare una funzione del genere per te ... è meno probabile. Devi fare qualcosa da solo. Inizia a fare qualcosa e torna quando rimani bloccato.
Felix Kling

7
Sì, ho letto Come chiedere e ho fatto qualcosa da solo, ma mi sono bloccato ed è per questo che l'ho chiesto. Lavoro su Android e ho poca conoscenza di javasript, motivo per cui non sono in grado di farlo da solo. In precedenza stavo usando un javascript diverso che ha funzionato ma non senza alcune limitazioni. Potrei non aver usato le parole giuste per porre questa domanda e mi dispiace per questo, ma per favore non pensare diversamente.
Ankit

1
Questo plugin potrebbe interessarti: github.com/julmot/jmHighlight . Può evidenziare le parole chiave separatamente o come termine, può evidenziare la corrispondenza con l'elemento personalizzato e il nome della classe e può anche cercare i segni diacritici. In alto ti permette di filtrare il contesto in cui cercare le corrispondenze.
tizio

1
Acquista modo seguente espressione regolare ... stackoverflow.com/a/45519242/2792959

Ho preparato un articolo su questo qui, exhesham.com/2017/11/20/…
Hesham Yassin

Risposte:


101

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:

Utilizzando 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 globall'espressione regolare di sostituzione.

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

Spero che questo aiuti i commentatori incuriositi.

Sostituzione dell'HTML su tutta la pagina web

per sostituire l'HTML per un'intera pagina web, dovresti fare riferimento al innerHTMLcorpo del documento.

document.body.innerHTML


Grazie mille per la tua risposta ma puoi anche dirmi come specificare il colore nello stesso javascript
Ankit

Puoi sostituire il "<span class='highlight'>"con "<span style='color: " + color + ";'>", il colore dovrebbe essere qualcosa del tipovar color = "#ff0000";
Yaniro

e se volessi evidenziare tutte le occorrenze di una parola su tutta la pagina? @guy mograbi
Naqvi

4
Usare una semplice "sostituzione" è una cattiva idea . Ho descritto il motivo qui: stackoverflow.com/a/32758672/3894981
amico,

2
Questa non è una grande idea perché tenterà di evidenziare tag / attributi / ecc. HTML. Ad esempio, cosa succederebbe in caso di: <img src="fox.jpg" /> Si otterrebbe un codice HTML non valido che sarebbe: <img src="<span class='highlight'>fox</span>.jpg" /> Non buono
dcporter7

46

Le soluzioni offerte qui sono piuttosto scadenti.

  1. Non puoi usare regex, perché in questo modo cerchi / evidenzi nei tag html.
  2. Non puoi usare regex, perché non funziona correttamente con UTF * (qualsiasi cosa con caratteri non latini / inglesi).
  3. Non puoi semplicemente fare un innerHTML.replace, perché questo non funziona quando i caratteri hanno una speciale notazione HTML, ad esempio &amp;per &, &lt;per <, &gt;per>, &auml;per ä, &ouml;per ö &uuml;per ü &szlig;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 toLowerCasese dovrebbe essere senza distinzione tra maiuscole e minuscole), aggiungi tutto prima indexofcome 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 textContentstringa).

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&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</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

Ottima risposta .. Il metodo sembra eccessivo, ma conciso! Sarò sicuramente interessato a fare un test di velocità con quel metodo poiché nel mio caso i risultati vengono caricati in modo pigro nel DOM (in quanto POSSONO esserci migliaia di risultati), curioso se questo metodo aggiungesse un'elevata latenza al carico pigro.
Pogrindis

5
Mi dispiace, ma nessuno dei tuoi argomenti è vero. 1. Puoi assolutamente usare una RegExp, semplicemente non dovresti cercare all'interno del valore HTML ma nel valore del testo di un elemento. 2. È possibile utilizzare assolutamente RegExp con i caratteri diacritici, come attuata in mark.js . 3. Le notazioni HTML verranno convertite nei caratteri effettivi nel DOM del browser, quindi anche tu le usi assolutamente!
tizio

1
@julmot; A 1: il che significa che devi scorrere ogni elemento, che è esattamente quello che faccio. A meno che non ti interessi perdere la formattazione, nel qual caso puoi cercare in document.body.innerText, che sarà piuttosto lento. 3. Non nel DOM, ma nella proprietà innerText o textContent di un elemento di testo. Il che significa di nuovo che è necessario iterare attraverso gli elementi di testo; non può essere fatto con regEx AFAIK. 2: Non so mark.js, ma eviterei tutto ciò che fa un jQuery.each, perché è dannatamente lento.
Stefan Steiger

1
@StefanSteiger 1. Quindi dovresti correggere la tua relazione decisionale, poiché dice che non possiamo cercare affatto con RegExp, il che non è vero 2. Non usa jQuery.each. Cosa te lo fa pensare? 3. Questo non è vero, almeno in Firefox. &auml;ad esempio, verrà convertito nel carattere effettivo, anche quando si utilizza innerHTML.
tizio

1
Ciao @StefanSteiger In realtà, sto usando le tue soluzioni. Questo è perfetto. Ma c'è qualche problema come, If II have a P In cui ci sono due span e uno span ha dati come Diploma MSBTE e il secondo span ha dati 2012. Ora se la stringa che voglio evidenziare è Diploma MSBTE 2012, l'intera stringa quindi ho controllato che non funziona, Se tutto ciò che sta per corrispondere è presente in un intervallo, allora funziona, ma se il contenuto del testo è in tag diff Non funziona. Puoi dirmi qualcosa a riguardo?
ganeshk

41

Perché usare una funzione di evidenziazione autoprodotta è una cattiva idea

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:

  • Dovresti rimuovere i nodi di testo con elementi HTML per evidenziare le tue corrispondenze senza distruggere gli eventi DOM e innescare la rigenerazione DOM più e più volte (come sarebbe il caso ad esempio innerHTML)
  • Se vuoi rimuovere gli elementi evidenziati dovresti rimuovere gli elementi HTML con il loro contenuto e devi anche combinare i nodi di testo divisi per ulteriori ricerche. Ciò è necessario perché ogni plug-in di evidenziatore cerca corrispondenze all'interno dei nodi di testo e se le tue parole chiave verranno suddivise in più nodi di testo non verranno trovate.
  • Dovresti anche creare dei test per assicurarti che il tuo plugin funzioni in situazioni a cui non hai pensato. E sto parlando di test cross-browser!

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.

Usa un plugin esistente

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.

Dai un'occhiata a mark.js

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:

  • cercare le parole chiave separatamente invece del termine completo
  • segni diacritici della mappa (Ad esempio se "justo" deve corrispondere anche a "justò")
  • ignora le corrispondenze all'interno degli elementi personalizzati
  • usa un elemento di evidenziazione personalizzato
  • usa la classe di evidenziazione personalizzata
  • mappare sinonimi personalizzati
  • cerca anche all'interno di iframe
  • ricevere termini non trovati

DEMO

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


4
L'evidenziazione del testo da sola non è un motivo sufficiente per includere jQuery.
Roy,

10
@ Roy l'ho preso a cuore. Buone notizie, a partire dalla v6.0.0 mark.js ha rinunciato alla dipendenza jQuery e ora lo rende facoltativamente utilizzabile come plug-in jQuery.
amico

Tutto vero, tranne: il 1 ° punto non è possibile, perché non puoi ottenere gestori di eventi registrati, e anche se potessi, non potresti impostare funzioni anonime ... 2 °: mark.js non trova nemmeno il testo tra due tag, ad es. <span> s </span> ed non troverà sed ... 3 °: ogni volta che arriva un browser (inclusa la nuova versione) che non l'hai ancora testato, potrebbe rompersi. Questo è sempre vero, non importa quanti test scrivi. A 17kb, i voti sono troppo grandi per quello che fa.
Stefan Steiger

Quali punti ti riferisci a @StefanSteiger? Non posso dire qualcosa al primo punto senza queste informazioni. Tuttavia, il secondo commento è sbagliato, mark.js può trovare corrispondenze tra i tag, utilizzando l' acrossElementsopzione. 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.
tizio

@ Dude: I tre punti dopo il primo paragrafo. Ah, ok, manca quell'opzione nella demo che ho visto. In tal caso, potrebbe avere un senso. Tuttavia, trovo che sia troppo grande.
Stefan Steiger

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

3
Mohit, benvenuto in SO. Qualche descrizione del codice sarebbe carino!
Nippey

non dovrebbe esserci un modo per selezionare il testo senza creare un altro nodo?
Dave Gregory

@ user191433 la domanda non riguarda solo la selezione del testo, ma anche l'applicazione degli stili. Per questo hai bisogno di un nodo.
Christophe

Promemoria / suggerimento che JavaScript si 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.
MarkHu

1
La risposta di PS Mohit su stackoverflow.com/questions/7991474/… è una variante più semplificata di questo codice. (ad esempio, omettendo le variabili di inizio e fine che sono solo diagnostiche / non funzionali qui.)
MarkHu

7

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

Questo funziona perfettamente per me quando il blocco di testo che sto cercando di evidenziare contiene tag HTML.
John Chapman

Puoi anche modificare la funzione per accettare più parole tramite il simbolo pipe regexp, ad esempioone|two|three
Klemen Tušar

Non sostituirà il testo se la fine del testo ha un >carattere. Modifica la regex usando (?!([^<]+)?<)per farla funzionare.
Archie Reyes

Modificato come richiesto.
Klemen Tušar

Perfetto! Questo è il migliore per me
marco burrometo

5

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

Questa era l'unica soluzione regex che ha funzionato per me senza scherzare con <img src="word">o <a href="word">.
yvesmancera

1
Regola d'oro: mai. Uso. Regolare. Espressioni. Per. Mess. Di. Con. XML.
ScottMcGready

5

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

Questo ha funzionato bene per me, ma ha anche bisogno di un modo per "deselezionare" '
jwzumwalt

4

Semplice esempio TypeScript

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

3

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.

JSFIDDLE DEMO


innerHTMLè pericoloso. Eliminerà gli eventi.
tizio

2
Anche questo non funziona correttamente perché, ad esempio, se entri nel JSFIDDLE "Lorem", ne contrassegna solo la prima istanza.
agm1984

1
Hai solo bisogno di sostituire tutte le occorrenze della parola chiave. ecco un esempio con regex a livello globale jsfiddle.net/de5q704L/73
kasper Taeymans,

2

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


oh questo è geniale. usalo semplicemente in questo modo: selection.setBaseAndExtent (wantedNode, 0, wantedNode, 1); per evidenziare l'unico nodo di cui hai bisogno. e funziona con Gutenberg
tonyAndr

1

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


0

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


-1

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);
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.