12 ответов:
вы можете использовать jquery выделить эффект.
но если вас интересует исходный код javascript, взгляните на то, что я получил Просто скопируйте вставить в HTML, откройте файл и нажмите кнопку "выделить" - это должно выделить слово "лиса". Производительность мудрый я думаю, что это будет делать для небольшого текста и одного повторения (как вы указали)
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>изменения:
используя
replaceЯ вижу, что этот ответ приобрел некоторую популярность, я думал, что могу добавить к нему. Вы также можете легко использовать вместо
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");или для нескольких вхождений (не относится к вопросу, но был задан в комментариях) вы просто добавляете
globalв регулярном выражении replace.
"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");надеюсь, это поможет заинтригованным комментаторам.
замена HTML на всю веб-страницу
to замените HTML для всей веб-страницы, вы должны обратиться к
innerHTMLтело документа.
document.body.innerHTML
решения, предлагаемые здесь, довольно плохие.
- вы не можете использовать регулярное выражение, потому что таким образом вы выполняете поиск/выделение в тегах html.
- вы не можете использовать регулярное выражение, потому что оно не работает должным образом с UTF* (ничего с нелатинскими/английскими символами).
- вы не можете просто сделать innerHTML.заменить, потому что это не работает, когда символы имеют специальную нотацию HTML, например
&для &,<для > для >,äдля ä,öдля...üдля üßдля β, etc.что нужно делать:
цикл через HTML-документ, найти все текстовые узлы, получить
textContent, получить положение выделенного текста сindexOf(опциональноtoLowerCaseесли он должен быть нечувствительным к регистру), добавьте все передindexofкакtextNode, добавьте соответствующий текст с выделенным промежутком и повторите для остальной части textnode (строка выделения может произойти несколько раз вtextContentстрока).вот код для этого:
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 };тогда вы можете использовать его следующим образом:
function TestTextHighlighting(highlightText) { var container = document.getElementById("testDocument"); InstantSearch.highlight(container, highlightText); }вот пример 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>кстати, если вы ищете в базе данных с
LIKE,
например,WHERE textField LIKE CONCAT('%', @query, '%')[что вы не должны делать, вы должны использовать полнотекстовый поиск или Lucene], тогда вы можете избежать каждого символа с помощью \ и добавить SQL-escape-оператор, который вы найдете специальным символы, которые являются подобными выражениями.например
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'и значение @query не
'% completed'но'\%\ \c\o\m\p\l\e\t\e\d'(протестировано, работает с SQL-сервером и PostgreSQL, а также любой другой системой СУБД, которая поддерживает ESCAPE)
a revised typescript-version:
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использование:
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
почему использование самодельной функции подсветки является плохой идеей
причина, по которой это, вероятно, плохая идея, чтобы начать строить свою собственную функцию подсветки с нуля, потому что вы, безусловно, столкнетесь с проблемами, которые другие уже решили. Проблемы:
- вам нужно будет удалить текстовые узлы с элементами HTML, чтобы выделить ваши матчи, не разрушая события DOM и не вызывая регенерацию DOM снова и снова (что было бы в случае с например,
innerHTML)- если вы хотите удалить выделенные элементы, вам придется удалить HTML-элементы с их содержимым, а также объединить разделенные текстовые узлы для дальнейшего поиска. Это необходимо, потому что каждый плагин highlighter ищет внутри текстовых узлов совпадения, и если ваши ключевые слова будут разбиты на несколько текстовых узлов, они не будут найдены.
- также необходимо построить тесты, чтобы убедиться, что ваш плагин работает в ситуациях, которые вы не мысль. И я говорю о кросс-браузерных тестах!
звучит сложно? Если вы хотите, чтобы некоторые функции, такие как игнорирование некоторых элементов из подсветки, диакритическое отображение, отображение синонимов, поиск внутри iframes, поиск отдельных слов и т. д. это становится все более и более сложным.
использовать существующий плагин
при использовании существующего, хорошо реализованного плагина вам не нужно беспокоиться о вышеназванных вещах. В статье 10 jQuery текстовый маркер Плагины on Sitepoint сравнивает популярные плагины маркеров.
посмотреть Марк.js
Марк.js это такой плагин, который написан на чистом JavaScript, но также доступен как плагин jQuery. Он был разработан, чтобы предложить больше возможностей, чем другие плагины с вариантами:
- поиск по ключевым словам отдельно вместо полного термина
- карта диакритиками (Например, если "justo" должен также соответствовать "justò")
- игнорировать совпадения внутри пользовательских элементов
- использовать пользовательский элемент подсветки
- использовать пользовательский класс подсветки
- карта пользовательских синонимов
- поиск также внутри iframes
- получить не найденные термины
вы можете ознакомиться эта скрипка.
использование пример:
// Highlight "keyword" in the specified context $(".context").mark("keyword"); // Highlight the custom regular expression in the specified context $(".context").markRegExp(/Lorem/gmi);это бесплатный и разработанный с открытым исходным кодом на GitHub (ссылка на проект).
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); }
у меня та же проблема, куча текста приходит через запрос xmlhttp. Этот текст имеет формат html. Мне нужно выделить каждое событие.
str='<img src="brown fox.jpg" title="The brown fox" />' +'<p>some text containing fox.</p>'проблема в том, что мне не нужно выделять текст в теги. Например, мне нужно выделить fox:
теперь я могу заменить его на:
var word="fox"; word="(\b"+ word.replace(/([{}()[\]\.?*+^$|=!:~-])/g, "\") + "\b)"; var r = new RegExp(word,"igm"); str.replace(r,"<span class='hl'></span>")чтобы ответить на ваш вопрос: вы можете оставить g в параметрах регулярного выражения, и только первое вхождение будет заменено, но это все еще один в img src свойство и уничтожает тег изображения:
<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span class='hl'>fox</span> />вот как я решил это, но было интересно, есть ли лучший способ, что-то я пропустил в регулярных выражениях:
str='<img src="brown fox.jpg" title="The brown fox" />' +'<p>some text containing fox.</p>' var word="fox"; word="(\b"+ word.replace(/([{}()[\]\.?*+^$|=!:~-])/g, "\") + "\b)"; var r = new RegExp(word,"igm"); str.replace(/(>[^<]+<)/igm,function(a){ return a.replace(r,"<span class='hl'></span>"); });
простой пример машинописного текста
Примечание: хотя я согласен с @Stefan во многих вещах, мне нужно было только простой подсветка матч:
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)); } } }и затем построение фактического результата:
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; } } }
вот мое регулярное выражение чисто JavaScript решение:
function highlight(text) { document.body.innerHTML = document.body.innerHTML.replace( new RegExp(text + '(?!([^<]+)?<)', 'gi'), '<b style="background-color:#ff0;font-size:100%">$&</b>' ); }
нашел выделить плагин, чтобы быть лучшим матчем, с ним вы можете выделить часть содержания:
$('li').выделите ('bla');
мне было интересно, что тоже, вы могли бы попробовать то, что я узнал на этой пост.
Я:
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>вы также можете попробовать его здесь: http://henriquedonati.com/projects/Extension/extension.html
xc
ни одно из других решений не соответствует моим потребностям, и хотя решение Стефана Штайгера работало так, как я ожидал, я нашел его слишком многословным.
следующая моя попытка:
/** * 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>Я бы также рекомендовал использовать что-то вроде escape-string-regexp если ваши ключевые слова могут иметь специальные символы, которые должны быть экранированы в регулярных выражениях:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
Так как HTML5 вы можете использовать
<mark></mark>теги для выделения текста. Вы можете использовать javascript для переноса некоторого текста/ключевого слова между этими тегами. Вот небольшой пример того, как пометить и снять пометку текста.
С помощью surroundContents() метод ряд тип. Его единственным аргументом является элемент, который будет обертывать этот диапазон.
function styleSelected() { bg = document.createElement("span"); bg.style.backgroundColor = "yellow"; window.getSelection().getRangeAt(0).surroundContents(bg); }
Comments