Comment mettre du texte en surbrillance en utilisant javascript

98

Quelqu'un peut-il m'aider avec une fonction javascript qui peut mettre en évidence du texte sur une page Web. Et l'exigence est de - mettre en évidence une seule fois, pas comme mettre en évidence toutes les occurrences du texte comme nous le faisons en cas de recherche.

Ankit
la source
4
Si vous publiez le code de la fonction, nous pourrions vous aider. Si vous nous demandez de créer une telle fonction pour vous ... c'est moins probable. Vous devez faire quelque chose par vous-même. Commencez à faire quelque chose et revenez lorsque vous êtes coincé.
Felix Kling
7
OUI, j'ai lu Comment demander et j'ai fait quelque chose par moi-même mais je suis resté coincé et c'est pourquoi j'ai demandé. Je travaille sur Android et j'ai peu de connaissances en javasript, c'est pourquoi je ne suis pas capable de le faire moi-même. Auparavant, j'utilisais un autre javascript qui faisait le travail mais non sans certaines limitations. Je n'ai peut-être pas utilisé les bons mots en posant cette question et j'en suis désolé, mais ne pensez pas autrement.
Ankit
1
Ce plugin peut vous intéresser: github.com/julmot/jmHighlight . Il peut mettre en évidence des mots-clés séparément ou en tant que terme, peut mettre en évidence la correspondance avec votre élément personnalisé et votre nom de classe et peut également rechercher des signes diacritiques. En plus, il vous permet de filtrer le contexte dans lequel rechercher des correspondances.
dude
1
Commander en suivant la manière regex ... stackoverflow.com/a/45519242/2792959
J'ai préparé un article à ce sujet ici, exhesham.com/2017/11/20/…
Hesham Yassin

Réponses:

101

Vous pouvez utiliser l' effet de surbrillance jquery .

Mais si vous êtes intéressé par le code javascript brut, jetez un œil à ce que j'ai obtenu. Copiez simplement et collez dans un HTML, ouvrez le fichier et cliquez sur "surligner" - cela devrait mettre en évidence le mot "renard". En termes de performances, je pense que cela conviendrait pour un petit texte et une seule répétition (comme vous l'avez spécifié)

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>

Modifications:

En utilisant replace

Je vois que cette réponse a gagné en popularité, j'ai pensé que je pourrais y ajouter. Vous pouvez également facilement utiliser replace

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

Ou pour les occurrences multiples (non pertinentes pour la question, mais qui ont été posées dans les commentaires), vous ajoutez simplement globall'expression régulière de remplacement.

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

J'espère que cela aidera les commentateurs intrigués.

Remplacement du HTML sur la page Web entière

pour remplacer le HTML d'une page Web entière, vous devez vous référer au innerHTMLcorps du document.

document.body.innerHTML

mec mograbi
la source
Merci beaucoup pour votre réponse mais pouvez-vous aussi me dire comment spécifier la couleur en javascript lui
Ankit
Vous pouvez remplacer le "<span class='highlight'>"par "<span style='color: " + color + ";'>", la couleur devrait être quelque chose commevar color = "#ff0000";
Yaniro
et si je veux mettre en évidence toutes les occurrences d'un mot sur toute la page? @guy mograbi
Baqer Naqvi
4
Utiliser un simple «remplacement» est une mauvaise idée . J'ai décrit pourquoi ici: stackoverflow.com/a/32758672/3894981
dude
2
Ce n'est pas une bonne idée car cela tentera de mettre en évidence les balises / attributs HTML / etc. Par exemple, que se passerait-il dans le cas de: <img src="fox.jpg" /> Vous obtiendriez un code HTML non valide qui ressemblerait à: <img src="<span class='highlight'>fox</span>.jpg" /> Pas bon
dcporter7
46

Les solutions proposées ici sont assez mauvaises.

  1. Vous ne pouvez pas utiliser de regex, car de cette façon, vous recherchez / mettez en surbrillance les balises html.
  2. Vous ne pouvez pas utiliser regex, car cela ne fonctionne pas correctement avec UTF * (tout ce qui contient des caractères non latins / anglais).
  3. Vous ne pouvez pas simplement faire un innerHTML.replace, car cela ne fonctionne pas lorsque les caractères ont une notation HTML spéciale, par exemple &amp;pour &, &lt;pour <, &gt;pour>, &auml;pour ä, &ouml;pour ö &uuml;pour ü &szlig;pour ß, etc.

Qu'as tu besoin de faire:

Parcourez le document HTML, trouvez tous les nœuds de texte, obtenez le textContent, obtenez la position du texte en surbrillance avec indexOf(avec un optionnel toLowerCases'il doit être insensible à la casse), ajoutez tout ce qui précède en indexoftant que textNode, ajoutez le texte correspondant avec une plage de surbrillance, et répétez pour le reste du noeud de texte (la chaîne de surbrillance peut apparaître plusieurs fois dans la textContentchaîne).

Voici le code pour cela:

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

};

Ensuite, vous pouvez l'utiliser comme ceci:

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

Voici un exemple de document 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>

Au fait, si vous recherchez dans une base de données avec LIKE,
par exemple WHERE textField LIKE CONCAT('%', @query, '%')[ce que vous ne devriez pas faire, vous devriez utiliser la recherche en texte intégral ou Lucene], alors vous pouvez échapper chaque caractère avec \ et ajouter une instruction SQL-escape, de cette façon vous trouverez des caractères spéciaux qui sont des expressions LIKE.

par exemple

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

et la valeur de @query n'est pas '%completed%'mais'%\c\o\m\p\l\e\t\e\d%'

(testé, fonctionne avec SQL-Server et PostgreSQL, et tous les autres systèmes SGBDR prenant en charge ESCAPE)


Une version dactylographiée révisée:

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 

Usage:

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
Stefan Steiger
la source
Excellente réponse. La méthode semble exagérée, mais concise! Sera certainement intéressé à faire un test de vitesse avec cette méthode, car dans mon cas, les résultats sont chargés paresseusement dans le DOM (car il PEUT y avoir des milliers de résultats), curieux de savoir si cette méthode ajouterait une latence élevée à la charge paresseuse.
Pogrindis
5
Désolé, mais aucun de vos arguments n'est vrai. 1. Vous pouvez absolument utiliser un RegExp, vous ne devez simplement pas rechercher dans la valeur HTML mais dans la valeur textuelle d'un élément. 2. Vous pouvez absolument utiliser RegExp avec des caractères diacritiques, mis en œuvre dans mark.js . 3. Les notations HTML seront converties en caractères réels dans le DOM du navigateur, vous les utilisez donc absolument!
mec
1
@julmot; À 1: ce qui signifie que vous devez parcourir chaque élément, ce qui est précisément ce que je fais. À moins que vous ne vous souciez pas de perdre la mise en forme, dans ce cas, vous pouvez rechercher dans document.body.innerText, ce qui sera assez lent. 3. Pas dans le DOM, mais dans la propriété innerText ou textContent d'un élément de texte. Ce qui signifie encore une fois que vous devez parcourir les éléments de texte; ne peut pas être fait avec regEx AFAIK. 2: Je ne sais pas mark.js, mais j'éviterais tout ce qui fait un jQuery.each, car c'est sacrément lent.
Stefan Steiger
1
@StefanSteiger 1. Ensuite, vous devez corriger votre raisonnement de décision, car il dit que nous ne pouvons pas du tout rechercher avec un RegExp, ce qui n'est pas vrai 2. Il n'utilise pas jQuery.each. Qu'est ce qui te fait penser ça? 3. Ce n'est pas vrai, du moins dans Firefox. &auml;par exemple sera converti en caractère réel, même lors de l'utilisation innerHTML.
mec du
1
Salut @StefanSteiger En fait, j'utilise vos solutions. Celui-ci est parfait. Mais il y a un problème comme, si II a un P dans lequel il y a deux travées et une travée contient des données comme Diploma MSBTE et la deuxième travée a des données 2012. Maintenant, si la chaîne que je veux mettre en évidence est Diploma MSBTE 2012, toute cette chaîne alors j'ai vérifié que cela ne fonctionne pas, si tout ce qui va correspondre est présent dans une seule étendue, cela fonctionne, mais si le contenu du texte est dans des balises diff alors Ça ne marche pas. Pouvez-vous nous dire quelque chose à ce sujet?
ganeshk
41

Pourquoi utiliser une fonction de mise en évidence personnalisée est une mauvaise idée

La raison pour laquelle c'est probablement une mauvaise idée de commencer à créer votre propre fonction de mise en évidence à partir de zéro est que vous rencontrerez certainement des problèmes que d'autres ont déjà résolus. Défis:

  • Vous auriez besoin de supprimer les nœuds de texte avec des éléments HTML pour mettre en évidence vos correspondances sans détruire les événements DOM et déclencher la régénération DOM encore et encore (ce qui serait le cas avec par exemple innerHTML)
  • Si vous souhaitez supprimer des éléments en surbrillance, vous devrez supprimer les éléments HTML avec leur contenu et combiner les nœuds de texte divisés pour des recherches ultérieures. Ceci est nécessaire car chaque plugin de surligneur recherche des correspondances à l'intérieur des nœuds de texte et si vos mots-clés seront divisés en plusieurs nœuds de texte, ils ne seront pas trouvés.
  • Vous devrez également créer des tests pour vous assurer que votre plugin fonctionne dans des situations auxquelles vous n'avez pas pensé. Et je parle de tests multi-navigateurs!

Cela semble compliqué? Si vous voulez certaines fonctionnalités comme ignorer certains éléments de la mise en évidence, le mappage des signes diacritiques, le mappage de synonymes, la recherche dans les iframes, la recherche de mots séparés, etc., cela devient de plus en plus compliqué.

Utiliser un plugin existant

Lorsque vous utilisez un plugin existant et bien implémenté, vous n'avez pas à vous soucier des choses nommées ci-dessus. L'article 10 des plugins de surligneur de texte jQuery sur Sitepoint compare les plugins de surligneur populaires.

Jetez un œil à mark.js

mark.js est un tel plugin qui est écrit en JavaScript pur, mais qui est également disponible en tant que plugin jQuery. Il a été développé pour offrir plus d'opportunités que les autres plugins avec des options pour:

  • rechercher des mots-clés séparément au lieu du terme complet
  • les signes diacritiques de la carte (par exemple, si "justo" doit également correspondre à "justò")
  • ignorer les correspondances à l'intérieur des éléments personnalisés
  • utiliser un élément de mise en évidence personnalisé
  • utiliser une classe de mise en évidence personnalisée
  • mapper des synonymes personnalisés
  • rechercher aussi à l'intérieur des iframes
  • recevoir les termes non trouvés

DEMO

Alternativement, vous pouvez voir ce violon .

Exemple d'utilisation :

// Highlight "keyword" in the specified context
$(".context").mark("keyword");

// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);

C'est gratuit et développé en open-source sur GitHub ( référence du projet ).

mec
la source
4
Mettre du texte en surbrillance à lui seul n'est pas une raison suffisante pour moi d'inclure jQuery.
Roy
10
@Roy J'ai pris ça à cœur. Bonne nouvelle, à partir de la v6.0.0, mark.js a renoncé à la dépendance jQuery et lui permet désormais de l'utiliser facultativement comme plugin jQuery.
mec
Tout est vrai, sauf: le 1er point n'est pas possible, car vous ne pouvez pas obtenir de gestionnaires d'événements enregistrés, et même si vous le pouviez, vous ne pouviez pas définir de fonctions anonymes ... 2e: mark.js ne trouve pas non plus de texte entre deux balises, par exemple <span> s </span> ed ne trouvera pas sed ... 3ème: chaque fois qu'un navigateur (y compris une nouvelle version) arrive et que vous ne l'avez pas encore testé, il risque de casser. C'est toujours vrai, quel que soit le nombre de tests que vous écrivez. À 17 ko, les notes sont trop importantes pour ce qu'elles font.
Stefan Steiger
À quels points faites-vous référence @StefanSteiger? Je ne peux pas dire quelque chose au premier point sans cette information. Cependant, le deuxième commentaire est faux, mark.js peut trouver des correspondances entre les balises, en utilisant l' acrossElementsoption. Et au troisième commentaire; mark.js n'est pas grand par rapport aux fonctionnalités qu'il offre. Et non, il est peu probable que quelque chose se brise à l'avenir, car mark.js a été testé, par exemple au démarrage de Chrome 30 et dans toutes les nouvelles versions avec des tests unitaires multi-navigateurs et il n'y a jamais eu de problèmes avec les versions à venir.
dude
@dude: Les trois points après le premier paragraphe. Ah, ok, il manque cette option dans la démo que j'ai regardée. Dans ce cas, cela pourrait avoir du sens. Mais encore, je trouve qu'il est trop grand.
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);
}
Mohit Kumar
la source
3
Mohit, bienvenue à SO. Une description du code serait bien!
Nippey
ne devrait-il pas y avoir un moyen de sélectionner du texte sans créer un autre nœud?
Dave Gregory
@ user191433 la question n'est pas seulement de sélectionner du texte, mais aussi d'appliquer des styles. Pour cela, vous avez besoin d'un nœud.
Christophe
Rappel / astuce que le JavaScript se span.style.backgroundColor = "yellow";traduit en CSS - style="background-color: yellow;"cette différence subtile entre le camelCase et la notation en pointillés m'a fait trébucher au début.
MarkHu
1
La réponse de PS Mohit à stackoverflow.com/questions/7991474/… est une variante plus simplifiée de ce code. (par exemple en omettant les variables de début et de fin qui sont uniquement diagnostiques / non fonctionnelles ici.)
MarkHu
7

Voici ma solution JavaScript pure regexp:

function highlight(text) {
    document.body.innerHTML = document.body.innerHTML.replace(
        new RegExp(text + '(?!([^<]+)?<)', 'gi'),
        '<b style="background-color:#ff0;font-size:100%">$&</b>'
    );
}
Klemen Tušar
la source
Cela fonctionne parfaitement pour moi lorsque le bloc de texte que j'essaie de mettre en évidence contient des balises HTML.
John Chapman
Vous pouvez également modifier la fonction pour accepter plusieurs mots via le symbole du tube d'expression one|two|three
régulière
Il ne remplacera pas le texte si la fin du texte a un >caractère. Modifiez le regex en utilisant (?!([^<]+)?<)pour qu'il fonctionne.
Archie Reyes
Modifié comme demandé.
Klemen Tušar
Parfait! C'est le meilleur pour moi
marco burrometo
5

J'ai le même problème, un tas de texte arrive via une requête xmlhttp. Ce texte est au format html. Je dois souligner chaque occurrence.

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

Le problème est que je n'ai pas besoin de mettre en évidence le texte des balises. Par exemple, je dois mettre en évidence le renard:

Maintenant, je peux le remplacer par:

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

Pour répondre à votre question: vous pouvez laisser de côté le g dans les options de regexp et seule la première occurrence sera remplacée mais c'est toujours celle de la propriété img src et détruit la balise image:

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

C'est ainsi que je l'ai résolu mais je me demandais s'il y avait une meilleure façon, quelque chose que j'ai manqué dans les expressions régulières:

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>");
});
HMR
la source
C'était la seule solution regex qui fonctionnait pour moi sans jouer avec <img src="word">ni <a href="word">.
yvesmancera
1
Règle d'or: jamais. Utilisation. Régulier. Expressions. À. Désordre. À propos. Avec. XML.
ScottMcGready
5

Aucune des autres solutions ne correspond vraiment à mes besoins, et bien que la solution de Stefan Steiger ait fonctionné comme je m'y attendais, je l'ai trouvée un peu trop verbeuse.

Voici ma tentative:

/**
 * 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>

Je recommanderais également d'utiliser quelque chose comme escape-string-regexp si vos mots-clés peuvent avoir des caractères spéciaux qui devraient être échappés dans les expressions rationnelles:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
elclans
la source
Cela a bien fonctionné pour moi, mais il faut aussi un moyen de "décocher" '
jwzumwalt
4

Exemple de typeScript simple

REMARQUE: Bien que je sois d'accord avec @Stefan sur de nombreux points, je n'avais besoin que d'une simple mise en évidence de correspondance:

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

Et puis construire le résultat réel:

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;
        }
    }
}
Slavo Vojacek
la source
3

Depuis HTML5, vous pouvez utiliser les <mark></mark>balises pour mettre du texte en surbrillance. Vous pouvez utiliser javascript pour insérer du texte / mot-clé entre ces balises. Voici un petit exemple de comment marquer et décocher du texte.

DÉMO JSFIDDLE

Kasper Taeymans
la source
innerHTMLest dangereux. Cela supprimera les événements.
dude
2
Cela ne fonctionne pas non plus correctement car, par exemple, si vous entrez dans le JSFIDDLE "Lorem", il n'en marque que la première instance.
agm1984
1
Bien, il vous suffit de remplacer toutes les occurrences du mot-clé. voici un exemple avec regex globalement jsfiddle.net/de5q704L/73
kasper Taeymans
2

Avance rapide jusqu'en 2019, l'API Web prend désormais en charge nativement la mise en évidence des textes:

const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);

Et vous êtes prêt à partir! anchorNodeest le nœud de départ de la sélection, focusNodeest le nœud de fin de sélection. Et, s'ils sont des nœuds de texte, offsetest l'index du caractère de début et de fin dans les nœuds respectifs. Voici la documentation

Ils ont même une démo en direct

JGuo
la source
oh c'est génial. utilisez-le simplement comme ceci: selection.setBaseAndExtent (desireNode, 0, desireNode, 1); pour mettre en évidence le seul nœud dont vous avez besoin. et ça marche avec Gutenberg
tonyAndr
1

Je me demandais que vous pourriez essayer ce que j'ai appris sur ce post.

J'ai utilisé:

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>

vous pouvez également l'essayer ici: http://henriquedonati.com/projects/Extension/extension.html

xc

Henrique Donati
la source
0

Nous si vous souhaitez également qu'il soit mis en évidence lors du chargement de la page, il existe une nouvelle façon.

il suffit d'ajouter #:~:text=Highlight%20These

essayez d'accéder à ce lien

/programming/38588721#:~:text=Highlight%20a%20text

Jovylle Bermudez
la source
-1

Utilisation de la méthode surroundContents () sur le type Range . Son seul argument est un élément qui encapsulera cette Range.

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