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.
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.
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:
replaceWidzę, ż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 globalwyraż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.
Aby zamienić kod HTML na całą stronę internetową, należy odwołać się do treści innerHTMLdokumentu.
document.body.innerHTML
"<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 dobry
Oferowane 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, toLowerCasejeśli nie ma rozróżniania wielkości liter), dołącz wszystko wcześniej indexofjako textNode, 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ć w textContentcią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
änp. zostanie przekonwertowany na właściwy znak, nawet jeśli jest używany innerHTML.
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.
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.
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:
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 ).
acrossElementsopcji. 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);
}
span.style.backgroundColor = "yellow";przekłada się na CSS style="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>'
);
}
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);
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>");
});
<img src="word">lub <a href="word">.
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;
}
}
}
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.
innerHTMLjest 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! anchorNodejest węzłem początkowym wyboru, focusNodejest węzłem końcowym wyboru. A jeśli są to węzły tekstowe, offsetjest indeksem początkowego i końcowego znaku w odpowiednich węzłach. Oto dokumentacja
Mają nawet demo na żywo
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
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
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);
}