Mettez un mot en surbrillance avec jQuery


101

J'ai essentiellement besoin de mettre en évidence un mot particulier dans un bloc de texte. Par exemple, faites comme si je voulais mettre en évidence le mot «dolor» dans ce texte:

<p>
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer dolor ullamcorper libero.
    Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

Comment puis-je convertir ce qui précède en quelque chose comme ceci:

<p>
    Lorem ipsum <span class="myClass">dolor</span> sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer <span class="myClass">dolor</span> ullamcorper
    libero. Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>

Est-ce possible avec jQuery?

Edit : Comme l'a souligné Sebastian , c'est tout à fait possible sans jQuery - mais j'espérais qu'il pourrait y avoir une méthode spéciale de jQuery qui vous permettrait de faire des sélecteurs sur le texte lui-même. J'utilise déjà beaucoup jQuery sur ce site, donc garder tout enveloppé dans jQuery rendrait les choses peut-être un peu plus ordonnées.


Cela peut également être intéressant: jquery.info/The-plugin-SearchHighlight
Eikern

Hé, j'ai écrit un plugin qui fait exactement cela - c'est comme le plugin Johann Burkard mlarsen posté, mais fonctionne avec des expressions régulières au lieu de chaînes. Vérifiez-le sur github et faites-moi savoir si vous avez besoin de fonctionnalités supplémentaires.

3
Au cas où vous auriez besoin d'une version clémente du plugin jQuery highlight: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör

1
Au lieu de mettre en évidence les mots avec un <span>, il est plus correct d'utiliser <mark>, sémantiquement parlant.
Jose Rui Santos

Salut, je suis à bord en retard, mais voici encore un autre extrait de code qui permet de mettre en évidence et de filtrer le texte en fonction des balises. J'espère que cela aidera quelqu'un jQuery Plugin pour la mise en évidence et le filtrage de texte
Jaspreet Chahal

Réponses:


85

Essayez la mise en évidence: texte JavaScript mettant en évidence le plugin jQuery .! Avertissement - Le code source disponible sur cette page contient un script d'extraction de devises cryptographiques, utilisez le code ci-dessous ou supprimez le script d'extraction du téléchargement sur le site Web. !

/*

highlight v4

Highlights arbitrary terms.

<http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html>

MIT license.

Johann Burkard
<http://johannburkard.de>
<mailto:jb@eaio.com>

*/

jQuery.fn.highlight = function(pat) {
 function innerHighlight(node, pat) {
  var skip = 0;
  if (node.nodeType == 3) {
   var pos = node.data.toUpperCase().indexOf(pat);
   if (pos >= 0) {
    var spannode = document.createElement('span');
    spannode.className = 'highlight';
    var middlebit = node.splitText(pos);
    var endbit = middlebit.splitText(pat.length);
    var middleclone = middlebit.cloneNode(true);
    spannode.appendChild(middleclone);
    middlebit.parentNode.replaceChild(spannode, middlebit);
    skip = 1;
   }
  }
  else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
   for (var i = 0; i < node.childNodes.length; ++i) {
    i += innerHighlight(node.childNodes[i], pat);
   }
  }
  return skip;
 }
 return this.length && pat && pat.length ? this.each(function() {
  innerHighlight(this, pat.toUpperCase());
 }) : this;
};

jQuery.fn.removeHighlight = function() {
 return this.find("span.highlight").each(function() {
  this.parentNode.firstChild.nodeName;
  with (this.parentNode) {
   replaceChild(this.firstChild, this);
   normalize();
  }
 }).end();
};

Essayez également la version "mise à jour" du script d'origine .

/*
 * jQuery Highlight plugin
 *
 * Based on highlight v3 by Johann Burkard
 * http://johannburkard.de/blog/programming/javascript/highlight-javascript-text-higlighting-jquery-plugin.html
 *
 * Code a little bit refactored and cleaned (in my humble opinion).
 * Most important changes:
 *  - has an option to highlight only entire words (wordsOnly - false by default),
 *  - has an option to be case sensitive (caseSensitive - false by default)
 *  - highlight element tag and class names can be specified in options
 *
 * Usage:
 *   // wrap every occurrance of text 'lorem' in content
 *   // with <span class='highlight'> (default options)
 *   $('#content').highlight('lorem');
 *
 *   // search for and highlight more terms at once
 *   // so you can save some time on traversing DOM
 *   $('#content').highlight(['lorem', 'ipsum']);
 *   $('#content').highlight('lorem ipsum');
 *
 *   // search only for entire word 'lorem'
 *   $('#content').highlight('lorem', { wordsOnly: true });
 *
 *   // don't ignore case during search of term 'lorem'
 *   $('#content').highlight('lorem', { caseSensitive: true });
 *
 *   // wrap every occurrance of term 'ipsum' in content
 *   // with <em class='important'>
 *   $('#content').highlight('ipsum', { element: 'em', className: 'important' });
 *
 *   // remove default highlight
 *   $('#content').unhighlight();
 *
 *   // remove custom highlight
 *   $('#content').unhighlight({ element: 'em', className: 'important' });
 *
 *
 * Copyright (c) 2009 Bartek Szopka
 *
 * Licensed under MIT license.
 *
 */

jQuery.extend({
    highlight: function (node, re, nodeName, className) {
        if (node.nodeType === 3) {
            var match = node.data.match(re);
            if (match) {
                var highlight = document.createElement(nodeName || 'span');
                highlight.className = className || 'highlight';
                var wordNode = node.splitText(match.index);
                wordNode.splitText(match[0].length);
                var wordClone = wordNode.cloneNode(true);
                highlight.appendChild(wordClone);
                wordNode.parentNode.replaceChild(highlight, wordNode);
                return 1; //skip added node in parent
            }
        } else if ((node.nodeType === 1 && node.childNodes) && // only element nodes that have children
                !/(script|style)/i.test(node.tagName) && // ignore script and style nodes
                !(node.tagName === nodeName.toUpperCase() && node.className === className)) { // skip if already highlighted
            for (var i = 0; i < node.childNodes.length; i++) {
                i += jQuery.highlight(node.childNodes[i], re, nodeName, className);
            }
        }
        return 0;
    }
});

jQuery.fn.unhighlight = function (options) {
    var settings = { className: 'highlight', element: 'span' };
    jQuery.extend(settings, options);

    return this.find(settings.element + "." + settings.className).each(function () {
        var parent = this.parentNode;
        parent.replaceChild(this.firstChild, this);
        parent.normalize();
    }).end();
};

jQuery.fn.highlight = function (words, options) {
    var settings = { className: 'highlight', element: 'span', caseSensitive: false, wordsOnly: false };
    jQuery.extend(settings, options);

    if (words.constructor === String) {
        words = [words];
    }
    words = jQuery.grep(words, function(word, i){
      return word != '';
    });
    words = jQuery.map(words, function(word, i) {
      return word.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
    });
    if (words.length == 0) { return this; };

    var flag = settings.caseSensitive ? "" : "i";
    var pattern = "(" + words.join("|") + ")";
    if (settings.wordsOnly) {
        pattern = "\\b" + pattern + "\\b";
    }
    var re = new RegExp(pattern, flag);

    return this.each(function () {
        jQuery.highlight(this, re, settings.element, settings.className);
    });
};

Il existe deux solutions, et elles sont contenues dans un fichier chacune. Je les ai ajoutés ci-dessus. Au moins, dans le pire des cas, ils seront toujours disponibles ici dans l'historique des modifications.
Erick Robertson

highlight v4 est un peu bogué. Il y a un correctif sur la page d'accueil de Burkard: johannburkard.de/blog/programming/javascript / ... Dans ce cas, ce n'était pas une bonne idée de copier le code ici; le lien pointe vers la dernière version (maintenant :)).
Lerin Sonberg

Au fait, la balise <mark> est probablement meilleure que la balise <span> ici.
unitario

1
Si vous recherchez un petit et léger, le plugin highlight jquery est en effet votre meilleur choix. C'est excellent pour mettre en évidence et supprimer les surbrillances correspondant au texte donné. Si vous avez besoin d'une expression régulière ou d'un autre support; cependant, vérifiez mark.js ou l'une des extensions et fourches pour la mise en évidence liée à la page de mise en évidence. J'utilise me surligner par rapport aux autres car la légèreté est très appréciée.
Greg

3
IMPORTANT: Johann Burkard a inclus un script de minage dans la source fournie sur son site Web !!!!!!
Lukars

42
function hiliter(word, element) {
    var rgxp = new RegExp(word, 'g');
    var repl = '<span class="myClass">' + word + '</span>';
    element.innerHTML = element.innerHTML.replace(rgxp, repl);
}
hiliter('dolor');

2
Vous ne voulez pas utiliser innerHTML tel qu'il a été introduit par Microsoft dans les années 80, puis abandonné à nouveau par Microsoft, comme d'habitude. Même si la plupart des navigateurs le prennent en charge, c'est tout sauf le standard W3C.
Steve K

21
Que devriez-vous utiliser à la place de innerHTML?
Kebman

15
@Sir Ben Benji: Je pense que vous confondez innerHTML avec innerText (l'alternative développée par Microsoft à textContent, qui est en effet un anathème à la spécification). innerHTML a peut-être commencé comme une extension Microsoft mais n'a en aucun cas été «abandonné»; il est pris en charge par tous les principaux navigateurs depuis le tout début des années 2000 et fait partie de HTML5 (dès 2008): w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml Il est toujours présent dans le dernier révision sur w3.org/TR/DOM-Parsing . Voir aussi w3.org/TR/html5/references.html#refsDOMPARSING
Jay Dansand

1
Pas vraiment une bonne solution. Je viens de l'utiliser, mais si je recherche par exemple «personne», il remplace également toutes les classes et éléments html par «personne». Et les minuscules et les majuscules ne sont pas non plus intégrées. var rgxp = new RegExp ("(\\ b" + mot + "\\ b)", "gim"); corrigé cela, mais je pense que le code ne doit pas remplacer les éléments html.
Richard Lindhout

33

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. Cela inclut des plugins de réponses à cette question.

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


11

Voici une variante qui ignore et préserve la casse:

jQuery.fn.highlight = function (str, className) {
    var regex = new RegExp("\\b"+str+"\\b", "gi");

    return this.each(function () {
        this.innerHTML = this.innerHTML.replace(regex, function(matched) {return "<span class=\"" + className + "\">" + matched + "</span>";});
    });
};

6
Cela fonctionne pour le texte brut, mais cela ne semble pas exclure les balises et les attributs. ie Recherchez "lass" lorsque vous avez un attribut de classe sur un div dans votre innerHTML.
Jonathan

Comment cette fonction est-elle appelée?
jiy

innerHTMLest le mal, voyez ma réponse ici. De plus, \\bne fonctionne pas pour les caractères Unicode. De plus, cette fonction manque presque tout, par exemple la recherche à l'intérieur des enfants imbriqués.
dude

3

Vous pouvez utiliser la fonction suivante pour mettre en évidence n'importe quel mot de votre texte.

function color_word(text_id, word, color) {
    words = $('#' + text_id).text().split(' ');
    words = words.map(function(item) { return item == word ? "<span style='color: " + color + "'>" + word + '</span>' : item });
    new_words = words.join(' ');
    $('#' + text_id).html(new_words);
    }

Ciblez simplement l'élément qui contient le texte, en choisissant le mot à coloriser et la couleur de votre choix.

Voici un exemple :

<div id='my_words'>
This is some text to show that it is possible to color a specific word inside a body of text. The idea is to convert the text into an array using the split function, then iterate over each word until the word of interest is identified. Once found, the word of interest can be colored by replacing that element with a span around the word. Finally, replacing the text with jQuery's html() function will produce the desired result.
</div>

Utilisation ,

color_word('my_words', 'possible', 'hotpink')

entrez la description de l'image ici

Azle a également une fonction intéressante pour cela. Il utilise des classes donc attribuez simplement un nom de classe à n'importe quel bloc de texte que vous souhaitez cibler.

az.style_word("target_class", target_instance, {
     "this_class" : "pink_word",
     "word" : "possible", // list any CSS styling after this line ...
     "color" : "hotpink", 
     "font-weight" : "bold"
})

2

Vous pouvez utiliser mon plugin de surbrillance jQuiteLight , qui peut également fonctionner avec des expressions régulières.

Pour installer en utilisant type npm :

npm install jquitelight --save

Pour installer à l'aide du bower type de :

bower install jquitelight 

Usage:

// for strings
$(".element").mark("query here");
// for RegExp
$(".element").mark(new RegExp(/query h[a-z]+/));

Utilisation plus avancée ici


@ user3631654 non c'est un plugin différent. Mon plugin peut fonctionner avec RegExp et dispose d'une fonctionnalité de mise en évidence intelligente. Si vous avez inclus le plugin que vous avez mentionné avant ce plugin, vous pouvez l'obtenir en utilisantvar oldMark = $.fn.mark.noConflict()
iamawebgeek

On dirait que jquery.mark a une méthode markRegExp()pour mettre également en évidence les expressions régulières personnalisées. Cela ne devrait donc pas être un argument.
user3631654

Et @zazu, que voulez-vous dire par «mise en évidence intelligente»?
user3631654

@ user3631654 si vous activez la mise en surbrillance intelligente et passez un mot "conséqunce", cela mettra également en évidence le mot "conséquences" et ses autres formes, mais si vous passez "the" ou "bla", il ne prendrait pas "thème" ou "noir"
iamawebgeek

2

JSFiddle

Utilisations .each(), .replace(), .html(). Testé avec jQuery 1.11 et 3.2.

Dans l'exemple ci-dessus, lit le «mot-clé» à mettre en évidence et ajoute la balise span avec la classe «highlight». Le texte «mot-clé» est mis en surbrillance pour toutes les classes sélectionnées dans le .each().

HTML

<body>
   <label name="lblKeyword" id="lblKeyword" class="highlight">keyword</label>
   <p class="filename">keyword</p>
   <p class="content">keyword</p>
   <p class="system"><i>keyword</i></p>
</body>

JS

$(document).ready(function() {
   var keyWord = $("#lblKeyword").text(); 
   var replaceD = "<span class='highlight'>" + keyWord + "</span>";
   $(".system, .filename, .content").each(function() {
      var text = $(this).text();
      text = text.replace(keyWord, replaceD);
      $(this).html(text);
   });
});

CSS

.highlight {
    background-color: yellow;
}

1

Vous devez obtenir le contenu de la balise p et remplacer tous les dolors par la version en surbrillance.

Vous n'avez même pas besoin d'avoir jQuery pour cela. :-)


9
Mais c'est plus facile avec jQuery, n'est-ce pas? ;)
Eikern

7
cela peut être fait avec nokia 6310, vous n'avez même pas besoin d'un PC pour cela :-)
okliv

1

J'ai écrit une fonction très simple qui utilise jQuery pour itérer les éléments enveloppant chaque mot-clé avec une classe .highlight.

function highlight_words(word, element) {
    if(word) {
        var textNodes;
        word = word.replace(/\W/g, '');
        var str = word.split(" ");
        $(str).each(function() {
            var term = this;
            var textNodes = $(element).contents().filter(function() { return this.nodeType === 3 });
            textNodes.each(function() {
              var content = $(this).text();
              var regex = new RegExp(term, "gi");
              content = content.replace(regex, '<span class="highlight">' + term + '</span>');
              $(this).replaceWith(content);
            });
        });
    }
}

Plus d'informations:

http://www.hawkee.com/snippet/9854/


2
Cela ne recherche pas dans les éléments imbriqués, n'a aucune fonction pour supprimer les surbrillances et n'a aucune information de licence.
mec

Cela vous dérange-t-il de m'expliquer ce que signifie «gi» dans «new RegExp (terme,« gi »)»?
vuquanghoang

0

J'ai créé un référentiel sur un concept similaire qui change les couleurs des textes dont les couleurs sont reconnues par html5 (nous n'avons pas à utiliser les valeurs réelles #rrggbb et pourrions simplement utiliser les noms comme html5 normalisé environ 140 d'entre eux)

colors.js colors.js

$( document ).ready(function() {
	
	function hiliter(word, element) {
		var rgxp = new RegExp("\\b" + word + "\\b" , 'gi'); // g modifier for global and i for case insensitive 
		var repl = '<span class="myClass">' + word + '</span>';
		element.innerHTML = element.innerHTML.replace(rgxp, repl);
			
			};

	hiliter('dolor', document.getElementById('dolor'));
});
.myClass{

background-color:red;
}
<!DOCTYPE html>
<html>
	<head>
		<title>highlight</title>
		
		<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
	
		 <link href="main.css" type="text/css"  rel="stylesheet"/>
		 
	</head>
	<body id='dolor'>
<p >
    Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
</p>
<p>
    Quisque bibendum sem ut lacus. Integer dolor ullamcorper libero.
    Aliquam rhoncus eros at augue. Suspendisse vitae mauris.
</p>
 <script type="text/javascript" src="main.js" charset="utf-8"></script>
	</body>
</html>


-2

Est-il possible d'obtenir cet exemple ci-dessus:

jQuery.fn.highlight = function (str, className)
{
    var regex = new RegExp(str, "g");

    return this.each(function ()
    {
        this.innerHTML = this.innerHTML.replace(
            regex,
            "<span class=\"" + className + "\">" + str + "</span>"
        );
    });
};

ne pas remplacer le texte à l'intérieur des balises html comme, sinon, cela brise la page.


-2
$(function () {
    $("#txtSearch").keyup(function (event) {
        var txt = $("#txtSearch").val()
        if (txt.length > 3) {
            $("span.hilightable").each(function (i, v) {
                v.innerHTML = v.innerText.replace(txt, "<hilight>" + txt + "</hilight>");
            });

        }
    });
});

Jfiddle ici


hilightn'est pas d'élément HTML valide
user3631654

Ignorez simplement cet avertissement, <hilight> est votre élément personnalisé, vous pouvez écrire ce que vous voulez. Avez-vous vu le violon?
L.Grillo

@nickf mon script fait exactement la même chose de la réponse acceptée
L.Grillo
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.