Comment mettre en évidence un texte en utilisant javascript

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

54
demandé sur Ankit 2011-12-27 16:05:55

12 réponses

vous pouvez utiliser le jquery effet de surbrillance .

mais si vous êtes intéressé par le code javascript brut, jetez un oeil à ce que j'ai obtenu Il suffit de copier coller dans un HTML, d'ouvrir le fichier et de cliquer sur "Mettre en évidence" - cela devrait mettre en évidence le mot "fox". Performance sage, je pense que ce serait faire pour le petit texte et une seule répétition (comme vous l'avez indiqué)

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:

utilisant replace

je vois que cette réponse a gagné en popularité, j'ai pensé que je pourrais ajouter sur elle. Vous pouvez aussi facilement utiliser remplacer

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

ou pour les occurrences multiples (non pertinent pour la question, mais a été demandé dans les commentaires) vous ajoutez simplement global sur l'expression remplacer régulier.

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

Espérons que cette aide aux intrigués commentateurs.

remplacer le HTML sur toute la page web

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

document.body.innerHTML

55
répondu guy mograbi 2018-04-02 12:28:05

les solutions proposées ici sont assez mauvaises.

  1. vous ne pouvez pas utiliser regex, parce que de cette façon, vous recherchez/mettez en surbrillance dans les balises html.
  2. vous ne pouvez pas utiliser regex, parce qu'il ne fonctionne pas correctement avec UTF* (quelque chose avec des caractères non-latins/anglais).
  3. vous ne pouvez pas juste faire un innerHTML.remplacer, parce que cela ne fonctionne pas lorsque les caractères ont une notation HTML spéciale, par exemple &amp; for &, &lt; pour<, &gt; pour >, &auml; pour ä, &ouml; pour ö &uuml; pour ü &szlig; pour ß, etc.

Ce que vous devez faire:

boucle à travers le document HTML, trouver tous les noeuds de texte, obtenir le textContent , obtenir la position du surlignage-texte avec indexOf (avec une option toLowerCase si elle devrait être insensible à la casse), tout ajouter avant indexof comme textNode , ajoutez le texte correspondant avec une portée de surlignage, et répétez pour le reste du textnode (la chaîne de surlignage peut apparaître plusieurs fois dans la chaîne textContent ).

voici le code pour ceci:

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

};

, Alors 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>

soit dit en passant, si vous cherchez 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 fulltext-search ou Lucene], alors vous pouvez échapper à chaque caractère avec \ et Ajouter un SQL-escape-statement, qui whay vous trouverez des caractères spéciaux qui sont comme-des expressions.

p.ex.

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 SGBDR système qui prend en charge l'ÉVASION)


Une version révisée du texte dactylographié-version:

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 

Utilisation:

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
28
répondu Stefan Steiger 2018-10-03 07:52:07

Pourquoi utiliser une fonction de mise en évidence faite par soi-même est une mauvaise idée

la raison pour laquelle il est probablement une mauvaise idée de commencer à construire votre propre fonction de mise en évidence à partir de Zéro est parce que vous allez certainement rencontrer des problèmes que d'autres ont déjà résolus. Les défis:

  • vous devez supprimer les noeuds 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 par exemple avec innerHTML )
  • si vous voulez supprimer les éléments surlignés, vous devez supprimer les éléments HTML avec leur contenu et aussi combiner les noeuds de texte fragmentés pour des recherches ultérieures. Cela est nécessaire car chaque plugin highlighter recherche des correspondances dans les noeuds de texte et si vos mots-clés sont divisés en plusieurs noeuds de texte, ils ne seront pas trouvés.
  • vous auriez aussi besoin de construire des tests pour faire bien sûr, votre plugin fonctionne dans des situations auxquelles vous n'avez pas pensé. Et je parle de tests de navigation croisée!

ça a l'air compliqué? Si vous voulez certaines fonctionnalités comme ignorer certains éléments de mise en évidence, cartographie diacritique, cartographie synonymes, recherche à l'intérieur d'iframes, recherche de mots séparés, etc. cela devient de plus en plus compliqué.

utiliser un plugin existant

Lors de l'utilisation d'un bien mis en œuvre plugin, vous n'avez pas à vous inquiéter au-dessus nommé choses. L'article 10 jQuery sélection de texte plugins sur Sitepoint compare populaire surligneur plugins.

regardez mark.js

de la marque.js est un tel plugin qui est écrit en JavaScript pur, mais est également disponible comme jQuery plugin. Il a été conçu pour offrir plus de possibilités que les autres plugins avec des options pour:

  • rechercher les mots-clés séparément au lieu du terme complet
  • carte de signes diacritiques (Par exemple, si "justo" doit également correspondre "justò")
  • ignorer les matches à l'intérieur des éléments personnalisés
  • utiliser un élément de mise en évidence personnalisé
  • personnalisé mettant en évidence la classe
  • map custom synonymes
  • rechercher aussi à l'intérieur iframes
  • reçoivent pas trouvé termes

Démo

vous pouvez aussi voir ce violon .

exemple d'Usage :

// 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 ( projet de référence ).

20
répondu dude 2016-05-20 10:16:31
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);
}
8
répondu Mohit kumar 2018-07-10 20:01:58

j'ai le même problème, un paquet de texte arrive via une requête xmlhttp. Ce texte est 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 surligner le texte dans les balises. Par exemple, je dois mettre en évidence fox:

maintenant je peux le remplacer par:

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

pour répondre à votre question: vous pouvez laisser de côté les options G dans regexp et seule la première occurrence sera remplacé mais c'est toujours celui 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 la façon dont 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, "\")
    + "\b)";
var r = new RegExp(word,"igm");
str.replace(/(>[^<]+<)/igm,function(a){
    return a.replace(r,"<span class='hl'></span>");
});
4
répondu HMR 2012-10-19 06:38:55

exemple D'écriture simple

NOTE: Bien que je sois d'accord avec @Stefan sur bien des points, je n'avais besoin que d'un simple mise en évidence du match:

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 ensuite 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;
        }
    }
}
4
répondu Slavo Vojacek 2015-08-30 12:50:14

voici ma solution JavaScript regexp pure:

function highlight(text) {
    document.body.innerHTML = document.body.innerHTML.replace(
        new RegExp(text + '(?!([^<]+)?<)', 'gi'),
        '<b style="background-color:#ff0;font-size:100%">$&</b>'
    );
}
2
répondu techouse 2016-08-19 07:04:38

j'ai trouvé highlight plugin pour être le meilleur match, avec elle, vous pouvez mettre en surbrillance une partie du contenu :

$('li').highlight ('bla');

1
répondu Igor G. 2014-02-24 22:19:51

je me demandais que vous aussi, 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 aussi l'essayer ici: http://henriquedonati.com/projects/Extension/extension.html

xc

1
répondu Henrique Donati 2017-05-23 10:31:20

aucune des autres solutions ne correspond vraiment à mes besoins, et bien que la solution de Stefan Steiger ait fonctionné comme je l'espérais, je l'ai trouvé un peu trop verbeux.

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 recommande aussi 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 regexes:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
1
répondu elclanrs 2018-03-05 15:11:42

depuis HTML5, vous pouvez utiliser les balises <mark></mark> pour mettre le texte en surbrillance. Vous pouvez utiliser javascript pour envelopper du texte/mot clé entre ces balises. Voici un petit exemple de la façon de marquer le texte.

JSFIDDLE DEMO

-1
répondu kasper Taeymans 2015-02-05 14:44:04

utilisant la méthode surroundContents () sur le type Range . Son seul argument est un élément qui enveloppera cette gamme.

function styleSelected() {
  bg = document.createElement("span");
  bg.style.backgroundColor = "yellow";
  window.getSelection().getRangeAt(0).surroundContents(bg);
}
-1
répondu arhoskins 2015-08-10 03:16:09