Podświetl słowo za pomocą jQuery

101

Zasadniczo muszę zaznaczyć określone słowo w bloku tekstu. Na przykład udawaj, że chcę podkreślić słowo „dolor” w tym tekście:

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

Jak przekonwertować powyższe na coś takiego:

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

Czy jest to możliwe dzięki jQuery?

Edycja : Jak wskazał Sebastian , jest to całkiem możliwe bez jQuery - ale miałem nadzieję, że może istnieć specjalna metoda jQuery, która pozwoli ci dokonać selektorów w samym tekście. Już teraz intensywnie używam jQuery na tej stronie, więc przechowywanie wszystkiego w jQuery może sprawić, że wszystko będzie bardziej uporządkowane.

nickf
źródło
To również może być interesujące: jquery.info/The-plugin-SearchHighlight
Eikern
Hej, napisałem wtyczkę, która robi dokładnie to - jest tak jak opublikowana przez mlarsena wtyczka Johanna Burkarda, ale działa z wyrażeniami regularnymi zamiast ciągów. Sprawdź to na githubie i daj mi znać, jeśli potrzebujesz dodatkowych funkcji.
3
Jeśli potrzebujesz łagodniejszej wersji wtyczki jQuery z podświetleniem: http://www.frightanic.com/2011/02/27/lenient-jquery-highlight-plugin-javascript/
Marcel Stör
1
Zamiast wyróżniać słowa za pomocą <span>, bardziej poprawne jest użycie <mark>, mówiąc semantycznie.
Jose Rui Santos
Cześć, jestem na pokładzie późno, ale oto kolejny fragment kodu, który pomaga wyróżniać i filtrować tekst na podstawie tagów. Mam nadzieję, że pomoże to komuś wtyczka jQuery do podświetlania i filtrowania tekstu
Jaspreet Chahal

Odpowiedzi:

85

Wypróbuj wyróżnienie: wtyczka jQuery do podświetlania tekstu JavaScript .! Ostrzeżenie - kod źródłowy dostępny na tej stronie zawiera skrypt eksplorujący kryptowalutę, użyj poniższego kodu lub usuń skrypt wydobywający z pobrania na stronie internetowej. !

/*

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

Wypróbuj także „zaktualizowaną” wersję oryginalnego skryptu .

/*
 * 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);
    });
};
mlarsen
źródło
Istnieją dwa rozwiązania i każde z nich jest zawarte w jednym pliku. Dodałem je powyżej. Przynajmniej w najgorszym przypadku zawsze będą dostępne tutaj w historii edycji.
Erick Robertson
Podświetlenie v4 jest trochę błędne. Na stronie domowej Burkarda jest poprawka: johannburkard.de/blog/programming/javascript/… W tym przypadku kopiowanie kodu tutaj nie było dobrym pomysłem; link wskazuje na najnowszą wersję (teraz :)).
Lerin Sonberg
Przy okazji, tag <mark> -tag jest prawdopodobnie lepszy niż tag <span> tutaj.
unitario
1
Jeśli szukasz małego i lekkiego, wtyczka Highlight jquery jest rzeczywiście najlepszym wyborem. Świetnie sprawdza się w podświetlaniu i usuwaniu zaznaczeń pasujących do danego tekstu. Jeśli potrzebujesz wyrażenia regularnego lub innego wsparcia; jednak sprawdź mark.js lub dowolne z rozszerzeń i widelców dla podświetlenia, do których link znajduje się na stronie z wyróżnieniem. Używam podświetlenia siebie nad innymi, ponieważ lekkość jest bardzo ceniona.
Greg,
3
WAŻNE: Johann Burkard umieścił skrypt eksploracyjny w źródle udostępnionym na swojej stronie internetowej !!!!!!
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');
Andrew Hedges
źródło
2
Nie chcesz używać innerHTML, tak jak został on wprowadzony przez firmę Microsoft w latach 80-tych, a później jak zwykle porzucony przez firmę Microsoft. Mimo że większość przeglądarek to obsługuje, jest to wszystko oprócz standardu W3C.
Steve K
21
Czego należy używać zamiast innerHTML?
Kebman
15
@Sir Ben Benji: Myślę, że mylisz innerHTML z innerText (opracowana przez firmę Microsoft alternatywa dla textContent, co jest rzeczywiście przekleństwem specyfikacji). innerHTML mogło zostać uruchomione jako rozszerzenie firmy Microsoft, ale w żaden sposób nie zostało „usunięte”; jest obsługiwany przez każdą większą przeglądarkę od wczesnych lat 2000 i jest częścią HTML5 (od 2008 roku): w3.org/TR/2008/WD-html5-20080610/dom.html#innerhtml Nadal jest obecny w najnowszej wersja na w3.org/TR/DOM-Parsing . Zobacz także w3.org/TR/html5/references.html#refsDOMPARSING
Jay Dansand
1
Niezbyt dobre rozwiązanie. Właśnie tego użyłem, ale jeśli wyszukuję na przykład „osoba”, to również zamienia wszystkie klasy i elementy html na „osoba”. Małe i wielkie litery również nie są zintegrowane. var rgxp = new RegExp ("(\\ b" + słowo + "\\ b)", "gim"); naprawiłem to, ale nadal myślę, że kod nie powinien zastępować elementów HTML.
Richard Lindhout
33

Dlaczego używanie własnej funkcji podświetlania to zły pomysł

Powodem, dla którego prawdopodobnie rozpoczęcie tworzenia własnej funkcji podświetlania od zera jest prawdopodobnie zły pomysł, jest to, że z pewnością napotkasz problemy, które inni już rozwiązali. Wyzwania:

  • Będziesz musiał usunąć węzły tekstowe z elementami HTML, aby podświetlić swoje dopasowania bez niszczenia zdarzeń DOM i ciągłego uruchamiania regeneracji DOM (co byłoby w przypadku np. innerHTML)
  • Jeśli chcesz usunąć podświetlone elementy, będziesz musiał usunąć elementy HTML z ich zawartością, a także połączyć podzielone węzły tekstowe do dalszych wyszukiwań. Jest to konieczne, ponieważ każda wtyczka zakreślacza wyszukuje dopasowania wewnątrz węzłów tekstowych i jeśli słowa kluczowe zostaną podzielone na kilka węzłów tekstowych, nie zostaną znalezione.
  • Będziesz także musiał zbudować testy, aby upewnić się, że wtyczka działa w sytuacjach, o których nie pomyślałeś. A ja mówię o testach w różnych przeglądarkach!

Brzmi skomplikowanie? Jeśli potrzebujesz funkcji, takich jak ignorowanie niektórych elementów z podświetlania, mapowanie znaków diakrytycznych, mapowanie synonimów, wyszukiwanie w ramkach iframe, wyszukiwanie oddzielnych słów itp., Staje się to coraz bardziej skomplikowane.

Użyj istniejącej wtyczki

Korzystając z istniejącej, dobrze zaimplementowanej wtyczki, nie musisz martwić się o powyższe rzeczy. Artykuł 10 Wtyczki wyróżniające tekst jQuery w witrynie Sitepoint porównuje popularne wtyczki wyróżniające. Obejmuje to wtyczki z odpowiedziami na to pytanie.

Spójrz na mark.js

mark.js to taka wtyczka, która jest napisana w czystym JavaScript, ale jest również dostępna jako wtyczka jQuery. Został opracowany, aby oferować więcej możliwości niż inne wtyczki z opcjami:

  • szukaj słów kluczowych oddzielnie zamiast całego terminu
  • odwzorowanie znaków diakrytycznych (na przykład jeśli „justo” powinno również pasować do „justò”)
  • ignoruj ​​dopasowania wewnątrz niestandardowych elementów
  • użyj niestandardowego elementu podświetlającego
  • użyj niestandardowej klasy podświetlania
  • mapować własne synonimy
  • szukaj także w ramkach iframe
  • otrzymać nie znalezione terminy

PRÓBNY

Alternatywnie możesz zobaczyć te skrzypce .

Przykład użycia :

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

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

Jest darmowy i opracowany jako open-source na GitHub ( odniesienie do projektu ).

koleś
źródło
11

Oto odmiana, która ignoruje i zachowuje wielkość liter:

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>";});
    });
};
bjarlestam
źródło
6
Działa to w przypadku zwykłego tekstu, ale nie wydaje się wykluczać tagów i atrybutów. tj. Wyszukaj „lass”, jeśli masz atrybut class w elemencie div w wewnętrznym HTML.
Jonathan
Jak wywoływana jest ta funkcja?
jiy,
innerHTMLjest zły, zobacz moją odpowiedź tutaj. Ponadto, \\bnie działa dla znaków Unicode. Ponadto ta funkcja pomija prawie wszystko, np. Wyszukiwanie wewnątrz zagnieżdżonych dzieci.
koleś
3

Możesz użyć następującej funkcji, aby podświetlić dowolne słowo w tekście.

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

Po prostu wskaż element zawierający tekst, wybierając słowo do pokolorowania i kolor .

Oto plik przykład :

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

Wykorzystanie ,

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

wprowadź opis obrazu tutaj

Azle ma również do tego fajną funkcję. Używa klas, więc po prostu przypisz nazwę klasy do dowolnego bloku tekstu, na który chcesz kierować.

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"
})
Cybernetyczny
źródło
2

Możesz użyć mojej wtyczki podświetlenia jQuiteLight , która może również działać z wyrażeniami regularnymi.

Aby zainstalować przy użyciu typu npm :

npm install jquitelight --save

Aby zainstalować za pomocą typu bower :

bower install jquitelight 

Stosowanie:

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

Bardziej zaawansowane użycie tutaj

iamawebgeek
źródło
@ user3631654 nie, to jest inna wtyczka. Moja wtyczka może współpracować z RegExp i ma funkcję inteligentnego podświetlania. Jeśli dołączyłeś wtyczkę, o której wspomniałeś wcześniej, możesz ją pobrać za pomocąvar oldMark = $.fn.mark.noConflict()
iamawebgeek
Wygląda na to, że jquery.mark ma metodę markRegExp()podświetlania niestandardowych wyrażeń regularnych. Więc to nie powinno być argumentem.
user3631654
@Zazu, co masz na myśli mówiąc o „inteligentnym podświetleniu”?
user3631654
@ user3631654, jeśli włączysz inteligentne podświetlenie i przekażesz słowo „consequnce”, podświetli ono również słowo „konsekwencje” i inne jego formy, ale jeśli przekażesz „the” lub „bla”, nie przyjmie „tematu” ani „czerni”
iamawebgeek
2

JSFiddle

Zastosowania .each(), .replace(),.html() . Testowane z jQuery 1.11 i 3.2.

W powyższym przykładzie odczytuje „słowo kluczowe”, które ma być podświetlone, i dodaje tag span z klasą „highlight”. Tekst „słowo kluczowe” jest podświetlony dla wszystkich wybranych klas w .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;
}
Van Peer
źródło
1

Musisz pobrać zawartość tagu p i zastąpić wszystkie znajdujące się w nim dolory podświetloną wersją.

Nie musisz nawet mieć do tego jQuery. :-)

Sebastian Hoitz
źródło
9
Ale z jQuery jest łatwiej, prawda? ;)
Eikern,
7
można to zrobić z nokią 6310, nie potrzebujesz nawet do tego komputera :-)
okliv
1

Napisałem bardzo prostą funkcję, która używa jQuery do iteracji elementów otaczających każde słowo kluczowe klasą .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);
            });
        });
    }
}

Więcej informacji:

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

Hawkee
źródło
2
To nie przeszukuje zagnieżdżonych elementów, nie ma funkcji usuwania wyróżnień i nie ma informacji o licencji.
koleś
Czy możesz mi wyjaśnić, co to jest „gi” w „nowym wyrażeniu regularnym (termin,„ gi ”)”?
vuquanghoang
0

Stworzyłem repozytorium na podobnej koncepcji, które zmienia kolory tekstów, których kolory są rozpoznawane przez html5 (nie musimy używać rzeczywistych wartości #rrggbb i możemy po prostu używać nazw tak, jak html5 ustandaryzował około 140 z nich)

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>

abe312
źródło
-2

Czy można uzyskać powyższy przykład:

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

nie zastępować tekstu wewnątrz tagów html, w przeciwnym razie spowoduje to uszkodzenie strony.

nickf
źródło
-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 tutaj

L.Grillo
źródło
hilightnie ma prawidłowego elementu HTML
user3631654
Po prostu zignoruj ​​to ostrzeżenie, <hilight> to Twój niestandardowy element, możesz pisać, co chcesz. Widziałeś skrzypce?
L.Grillo
@nickf mój skrypt robi dokładnie to samo, co zaakceptowana odpowiedź
L.Grillo