Czy ktoś może mi pomóc z funkcją javascript, która może podświetlać tekst na stronie internetowej. A wymaganiem jest - zaznaczenie tylko raz, a nie zaznaczanie wszystkich wystąpień tekstu, jak robimy to w przypadku wyszukiwania.
javascript
highlighting
Ankit
źródło
źródło
Odpowiedzi:
Możesz użyć efektu podświetlenia jQuery .
Ale jeśli jesteś zainteresowany surowym kodem javascript, spójrz na to, co mam. Po prostu skopiuj wklej do HTML, otwórz plik i kliknij "podświetl" - powinno to podświetlić słowo "lis". Pod względem wydajności myślę, że wystarczyłoby to dla małego tekstu i pojedynczego powtórzenia (tak jak określiłeś)
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>
Edycje:
Za pomocą
replace
Widzę, że ta odpowiedź zyskała popularność, pomyślałem, że mógłbym ją dodać. Możesz także łatwo skorzystać z wymiany
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");
Lub w przypadku wielu wystąpień (nie dotyczy pytania, ale zadano w komentarzach), po prostu dodaj
global
wyrażenie regularne zastępowania."the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");
Mam nadzieję, że to pomoże zaintrygowanym komentatorom.
Zastąpienie kodu HTML całej strony internetowej
Aby zamienić kod HTML na całą stronę internetową, należy odwołać się do treści
innerHTML
dokumentu.document.body.innerHTML
źródło
"<span class='highlight'>"
z"<span style='color: " + color + ";'>"
, kolor powinien być coś podobnegovar color = "#ff0000";
<img src="fox.jpg" />
Otrzymasz nieprawidłowy kod HTML, który będzie wyglądał następująco:<img src="<span class='highlight'>fox</span>.jpg" />
Niezbyt dobryOferowane tutaj rozwiązania są dość złe.
&
Dla &,<
dla <,>
dla>,ä
dla ä,ö
dla öü
dla üß
dla ß itp.Co musisz zrobić:
Zapętlaj się po dokumencie HTML, znajdź wszystkie węzły tekstowe, pobierz
textContent
, uzyskaj położenie podświetlonego tekstu za pomocąindexOf
(z opcjonalnym,toLowerCase
jeśli nie ma rozróżniania wielkości liter), dołącz wszystko wcześniejindexof
jakotextNode
, dołącz dopasowany tekst z podświetleniem, i powtórz dla pozostałej części węzła tekstowego (ciąg podświetlenia może wystąpić wtextContent
ciągu wielokrotnie ).Oto kod:
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 };
Następnie możesz go użyć w ten sposób:
function TestTextHighlighting(highlightText) { var container = document.getElementById("testDocument"); InstantSearch.highlight(container, highlightText); }
Oto przykładowy dokument 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äöüÄÖÜ</span> </div> </body> </html>
Nawiasem mówiąc, jeśli szukać w bazie danych z
LIKE
,np
WHERE textField LIKE CONCAT('%', @query, '%')
[czego nie powinien robić, trzeba zastosować pełny-przeszukania lub Lucene], a następnie można uciec każdy znak z \ i dodaj SQL-Escape-oświadczenie, w ten sposób znajdziesz znaki specjalne, które są wyrażeniami LIKE.na przykład
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
a wartość @query nie jest
'%completed%'
ale'%\c\o\m\p\l\e\t\e\d%'
(przetestowany, działa z SQL-Server i PostgreSQL oraz każdym innym systemem RDBMS obsługującym ESCAPE)
Poprawiona wersja maszynopisu:
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
Stosowanie:
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
źródło
ä
np. zostanie przekonwertowany na właściwy znak, nawet jeśli jest używanyinnerHTML
.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:
innerHTML
)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 wtyczek wyróżniających tekst jQuery w witrynie Sitepoint porównuje popularne wtyczki wyróżniające.
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:
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 ).
źródło
acrossElements
opcji. I do trzeciego komentarza; mark.js nie jest duży w porównaniu z funkcjami, które oferuje. I nie, jest mało prawdopodobne, że coś się zepsuje w przyszłości, ponieważ mark.js był testowany np. Uruchamiając Chrome 30 i we wszystkich nowszych wersjach z testami jednostkowymi między przeglądarkami i nigdy nie było żadnych problemów z nadchodzącymi wersjami.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); }
źródło
span.style.backgroundColor = "yellow";
przekłada się na CSSstyle="background-color: yellow;"
- ta subtelna różnica między camelCase a notacją przerywaną na początku mnie zaskoczyła.Oto moje rozwiązanie wyrażenia regularnego w czystym języku JavaScript:
function highlight(text) { document.body.innerHTML = document.body.innerHTML.replace( new RegExp(text + '(?!([^<]+)?<)', 'gi'), '<b style="background-color:#ff0;font-size:100%">$&</b>' ); }
źródło
one|two|three
>
znak. Zmodyfikuj wyrażenie regularne, używając(?!([^<]+)?<)
, aby działało.Żadne z innych rozwiązań nie odpowiadało moim potrzebom i chociaż rozwiązanie Stefana Steigera działało tak, jak się spodziewałem, uznałem je za zbyt rozwlekłe.
Oto moja próba:
/** * 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>
Zalecałbym również użycie czegoś takiego jak escape-string-regexp, jeśli słowa kluczowe mogą zawierać znaki specjalne, które musiałyby zostać zmienione w wyrażeniach regularnych:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
źródło
Mam ten sam problem, mnóstwo tekstu przychodzi przez żądanie xmlhttp. Ten tekst jest w formacie HTML. Muszę podkreślić każde wystąpienie.
str='<img src="brown fox.jpg" title="The brown fox" />' +'<p>some text containing fox.</p>'
Problem w tym, że nie muszę wyróżniać tekstu w tagach. Na przykład muszę zaznaczyć lisa:
Teraz mogę go zastąpić:
var word="fox"; word="(\\b"+ word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1") + "\\b)"; var r = new RegExp(word,"igm"); str.replace(r,"<span class='hl'>$1</span>")
Odpowiadając na pytanie: możesz pominąć g w opcjach wyrażenia regularnego i tylko pierwsze wystąpienie zostanie zastąpione, ale nadal jest to to we właściwości img src i niszczy tag obrazu:
<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span class='hl'>fox</span> />
Oto sposób, w jaki to rozwiązałem, ale zastanawiałem się, czy istnieje lepszy sposób, coś, czego brakuje mi w wyrażeniach regularnych:
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>"); });
źródło
<img src="word">
lub<a href="word">
.Prosty przykład języka TypeScript
UWAGA: Chociaż zgadzam się z @Stefanem w wielu sprawach, potrzebowałem tylko prostego podkreślenia dopasowania:
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)); } } }
A następnie konstruowanie rzeczywistego wyniku:
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; } } }
źródło
Od HTML5 możesz używać
<mark></mark>
tagów do podświetlania tekstu. Możesz użyć javascript do zawijania tekstu / słów kluczowych między tymi tagami. Oto mały przykład zaznaczania i odznaczania tekstu.JSFIDDLE DEMO
źródło
innerHTML
jest niebezpieczny. Usunie wydarzenia.Przewiń do 2019 r., Web API ma teraz natywną obsługę podświetlania tekstów:
const selection = document.getSelection(); selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
I jesteś gotowy!
anchorNode
jest węzłem początkowym wyboru,focusNode
jest węzłem końcowym wyboru. A jeśli są to węzły tekstowe,offset
jest indeksem początkowego i końcowego znaku w odpowiednich węzłach. Oto dokumentacjaMają nawet demo na żywo
źródło
Też się zastanawiałem, możesz spróbować tego, czego się nauczyłem w tym poście.
Użyłem:
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>
możesz też spróbować tutaj: http://henriquedonati.com/projects/Extension/extension.html
xc
źródło
Jeśli chcesz, aby był on również wyróżniany podczas ładowania strony, jest nowy sposób.
poprostu dodaj
#:~:text=Highlight%20These
spróbuj uzyskać dostęp do tego łącza
/programming/38588721#:~:text=Highlight%20a%20text
źródło
Użycie metody surroundContents () w typie Range . Jej jedynym argumentem jest element, który zawinie ten Range.
function styleSelected() { bg = document.createElement("span"); bg.style.backgroundColor = "yellow"; window.getSelection().getRangeAt(0).surroundContents(bg); }
źródło