Markeer een woord met jQuery

Ik moet eigenlijk een bepaald woord in een tekstblok markeren. Stel bijvoorbeeld dat ik het woord “dolor” in deze tekst wilde benadrukken:

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

Hoe converteer ik het bovenstaande naar iets als dit:

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

Is dit mogelijk met jQuery?

Bewerken: als Sebastianopgemerkt, dit is heel goed mogelijk zonder jQuery – maar ik hoopte dat er een speciale methode van jQuery zou zijn waarmee je doen selectors op de tekst zelf. Ik gebruik jQuery al intensief op deze site, dus als ik alles in jQuery zou houden, zou het misschien wat overzichtelijker worden.


Antwoord 1, autoriteit 100%

Probeer markeer: JavaScript tekst markeren jQuery plug-in.
Waarschuwing: de broncode die op deze pagina beschikbaar is, bevat een cryptocurrency-miningscript. Gebruik de onderstaande code of verwijder het mining-script uit het script dat van de website is gedownload.

/*
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:[email protected]>
*/
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();
};

Probeer ook de “bijgewerkte” versie van het originele script.

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

Antwoord 2, autoriteit 50%

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

Antwoord 3, autoriteit 45%

Waarom het een slecht idee is om een ​​zelfgemaakte markeerfunctie te gebruiken

De reden waarom het waarschijnlijk een slecht idee is om helemaal opnieuw te beginnen met het bouwen van uw eigen markeerfunctie, is omdat u zeker problemen tegenkomt die anderen al hebben opgelost. Uitdagingen:

  • Je zou tekstknooppunten met HTML-elementen moeten verwijderen om je overeenkomsten te markeren zonder DOM-gebeurtenissen te vernietigen en DOM-regeneratie keer op keer te activeren (wat het geval zou zijn met bijvoorbeeld innerHTML)
  • Als u gemarkeerde elementen wilt verwijderen, moet u HTML-elementen met hun inhoud verwijderen en ook de gesplitste tekstknooppunten combineren voor verdere zoekopdrachten. Dit is nodig omdat elke plug-in voor markeerstiften in tekstknooppunten zoekt naar overeenkomsten en als uw zoekwoorden worden opgesplitst in verschillende tekstknooppunten, worden ze niet gevonden.
  • Je zou ook tests moeten bouwen om er zeker van te zijn dat je plug-in werkt in situaties waar je niet aan hebt gedacht. En dan heb ik het over cross-browser tests!

Klinkt ingewikkeld? Als je bepaalde functies wilt, zoals het negeren van bepaalde elementen van markering, diakritische tekens, het toewijzen van synoniemen, zoeken in iframes, zoeken op gescheiden woorden, enzovoort, wordt dit steeds ingewikkelder.

Gebruik een bestaande plug-in

Als u een bestaande, goed geïmplementeerde plug-in gebruikt, hoeft u zich geen zorgen te maken over bovengenoemde zaken. Het artikel 10 jQuery-plug-ins voor tekstmarkeringop Sitepoint vergelijkt populaire highlighter-plug-ins. Dit omvat plug-ins met antwoorden op deze vraag.

Bekijk mark.js

mark.jsis zo’n plug-in die in pure JavaScript is geschreven, maar die ook beschikbaar is als jQuery-plug-in. Het is ontwikkeld om meer mogelijkheden te bieden dan de andere plug-ins met opties om:

  • zoek zoekwoorden afzonderlijk in plaats van de volledige term
  • diakritische tekens op de kaart (bijvoorbeeld als “justo” ook moet overeenkomen met “justò”)
  • negeer overeenkomsten in aangepaste elementen
  • gebruik een aangepast markeringselement
  • gebruik aangepaste markeringsklasse
  • aangepaste synoniemen toewijzen
  • zoek ook binnen iframes
  • niet gevonden termen ontvangen

DEMO

Als alternatief kun je deze vioolzien.

Gebruiksvoorbeeld:

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

Het is gratis en open-source ontwikkeld op GitHub (projectreferentie).


Antwoord 4, autoriteit 13%

Hier is een variant die hoofdletters negeert en behoudt:

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

Antwoord 5, autoriteit 3%

JSFiddle

Gebruikt .each(), .replace(), .html(). Getest met jQuery 1.11 en 3.2.

In het bovenstaande voorbeeld leest het ‘trefwoord’ dat moet worden gemarkeerd en voegt de span-tag toe aan de klasse ‘highlight’. De tekst ‘trefwoord’ is gemarkeerd voor alle geselecteerde klassen in de .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;
}

Antwoord 6, autoriteit 2%

Je kunt mijn highlight-plug-in jQuiteLightgebruiken, die ook met reguliere expressies kan werken.

Installatie met npmtypt u:

npm install jquitelight --save

Installeren met bowertype:

bower install jquitelight 

Gebruik:

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

Meer geavanceerd gebruik hier


Antwoord 7, autoriteit 2%

U kunt de volgende functiegebruiken om elk woord in uw tekst te markeren.

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

Gewoon het element targetendat de tekst bevat, het woord kiezenom in te kleuren en de kleurnaar keuze.

Hier is een voorbeeld:

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

Gebruik,

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


Antwoord 8

Je moet de inhoud van de p-tag ophalen en alle dolors erin vervangen door de gemarkeerde versie.

Je hoeft hiervoor niet eens jQuery te hebben. 🙂


Antwoord 9

Ik heb een heel eenvoudige functie geschreven die jQuery gebruikt om de elementen te herhalen die elk zoekwoord omhullen met een .highlight-klasse.

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

Meer info:

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


Antwoord 10

Other episodes