Хтось може мені допомогти з функцією javascript, яка може виділити текст на веб-сторінці. І вимога полягає у тому, щоб - виділяти лише один раз, а не як виділяти всі входження тексту, як це робимо у випадку пошуку.
Хтось може мені допомогти з функцією javascript, яка може виділити текст на веб-сторінці. І вимога полягає у тому, щоб - виділяти лише один раз, а не як виділяти всі входження тексту, як це робимо у випадку пошуку.
Відповіді:
Ви можете використовувати ефект підсвічування 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 для цілої веб-сторінки, слід звернутися до innerHTML
тіла документа.
document.body.innerHTML
"<span class='highlight'>"
з "<span style='color: " + color + ";'>"
, колір повинен бути що - щось на зразокvar color = "#ff0000";
<img src="fox.jpg" />
Ви отримаєте недійсний HTML, який виглядатиме так: <img src="<span class='highlight'>fox</span>.jpg" />
Не добре
Рішення, пропоновані тут, досить погані.
&
для &, <
для <, >
для>, ä
для ä, ö
для ö ü
для ü ß
для ß і т.д.Що потрібно зробити:
Прокрутіть документ HTML, знайдіть усі текстові вузли, отримайте textContent
, отримайте позицію тексту виділення за допомогою indexOf
(з необов’язковим, toLowerCase
якщо це не враховує регістр), додайте все до, indexof
як 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, '%')
[чого не слід робити, вам слід використовувати fulltext-search або Lucene], тоді ви можете уникнути кожного символу за допомогою \ та додати оператор SQL-escape-таким чином ви знайдете спеціальні символи, які є LIKE-виразами.
напр
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
а значення @query - ні '%completed%'
але'%\c\o\m\p\l\e\t\e\d%'
(протестовано, працює з SQL-сервером та PostgreSQL та будь-якою іншою системою СУБД, що підтримує ESCAPE)
Перероблена версія машинопису:
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
ä
наприклад, буде перетворено на дійсний символ, навіть під час використання innerHTML
.
Причина, чому, мабуть, погана ідея починати створювати власну функцію підсвічування з нуля, полягає в тому, що ви, безумовно, зіткнетеся з проблемами, які інші вже вирішили. Виклики:
innerHTML
)Звучить складно? Якщо ви хочете, щоб деякі функції, такі як ігнорування деяких елементів, виділення, відображення діакритики, відображення синонімів, пошук усередині фреймів, пошук окремих слів тощо, стають дедалі складнішими.
Використовуючи існуючий, добре реалізований плагін, вам не доведеться турбуватися про вищезазначені речі. У статті 10 jQuery текстові плагіни для виділення тексту на Sitepoint порівнюються популярні плагіни для виділення.
mark.js - це такий плагін, який написаний на чистому JavaScript, але також доступний як плагін jQuery. Він був розроблений, щоб запропонувати більше можливостей, ніж інші плагіни, з опціями:
Ви також можете побачити цю скрипку .
Приклад використання :
// Highlight "keyword" in the specified context
$(".context").mark("keyword");
// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);
Це безкоштовний і розроблений з відкритим кодом на GitHub ( посилання на проект ).
acrossElements
опцію. І до третього коментаря; mark.js не є великим порівняно з функціональними можливостями, які він пропонує. І ні, навряд чи щось зламається в майбутньому, оскільки mark.js тестувався, наприклад, запускаючи Chrome 30 та у всіх новіших версіях з крос-браузерними модульними тестами, і ніколи не виникало жодних проблем із майбутніми версіями.
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";
перекладає на CSS style="background-color: yellow;"
- спочатку мене спокусила тонка різниця між камелею і пунктиром.
Ось моє регулярне вираження чистого рішення 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
>
символ. Змініть регулярний вираз, використовуючи (?!([^<]+)?<)
його для роботи.
У мене така сама проблема, купу тексту надходить через запит xmlhttp. Цей текст має формат HTML. Мені потрібно виділити кожну подію.
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(r,"<span class='hl'>$1</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, "\\$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">
або <a href="word">
.
Жодне з інших рішень насправді не відповідало моїм потребам, і хоча рішення Стефана Штайгера спрацювало, як я очікував, мені здалося це занадто багатослівним.
Ось моя спроба:
/**
* 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);
ПРИМІТКА: Хоча я багато в чому погоджуюсь із @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;
}
}
}
З HTML5 ви можете використовувати <mark></mark>
теги для виділення тексту. Ви можете використовувати javascript для перенесення тексту / ключового слова між цими тегами. Ось невеликий приклад того, як позначати та знімати позначку з тексту.
innerHTML
небезпечно. Це видалить події.
Переходячи до 2019 року, веб-API тепер підтримує виділення текстів:
const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);
І вам добре їхати! anchorNode
є початковим вузлом виділення, focusNode
є вузлом закінчення виділення. І якщо це текстові вузли, offset
це індекс початкового та кінцевого символу у відповідних вузлах. Ось документація
У них навіть є демо в реальному часі
Мені теж було цікаво, що ви можете спробувати те, що я дізнався на цій посаді.
Я використав:
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
У нас, якщо ви також хочете, щоб це було виділено при завантаженні сторінки, є новий спосіб.
просто додайте #:~:text=Highlight%20These
спробуйте отримати доступ до цього посилання
/programming/38588721#:~:text=Highlight%20a%20text
Використання методу surroundContents () для типу Range . Його єдиним аргументом є елемент, який оберне цей діапазон.
function styleSelected() {
bg = document.createElement("span");
bg.style.backgroundColor = "yellow";
window.getSelection().getRangeAt(0).surroundContents(bg);
}