ใครช่วยฉันด้วยฟังก์ชันจาวาสคริปต์ที่สามารถเน้นข้อความบนหน้าเว็บได้ และข้อกำหนดคือ - ไฮไลต์เพียงครั้งเดียวไม่เหมือนกับการเน้นข้อความที่เกิดขึ้นทั้งหมดเหมือนที่เราทำในกรณีของการค้นหา
ใครช่วยฉันด้วยฟังก์ชันจาวาสคริปต์ที่สามารถเน้นข้อความบนหน้าเว็บได้ และข้อกำหนดคือ - ไฮไลต์เพียงครั้งเดียวไม่เหมือนกับการเน้นข้อความที่เกิดขึ้นทั้งหมดเหมือนที่เราทำในกรณีของการค้นหา
คำตอบ:
แต่ถ้าคุณสนใจโค้ดจาวาสคริปต์ดิบลองดูสิ่งที่ฉันได้รับเพียงคัดลอกวางลงใน 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
แทนที่นิพจน์ทั่วไป
"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" />
ไม่ดี
วิธีแก้ปัญหาที่นำเสนอนี้ค่อนข้างแย่
&
สำหรับ & <
สำหรับ <, >
for> ä
สำหรับä, ö
สำหรับö ü
สำหรับü ß
สำหรับßเป็นต้นสิ่งที่คุณต้องทำ:
ห่วงผ่านเอกสาร 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 ค้นหาหรือ Lucene] จากนั้นคุณสามารถหลบหนีตัวละครทุกตัวมี \ และเพิ่ม SQL หนีคำสั่งวิธีการที่ คุณจะพบอักขระพิเศษที่เป็นนิพจน์ LIKE
เช่น
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
และคุณค่าของ @query ไม่ใช่'%completed%'
แต่'%\c\o\m\p\l\e\t\e\d%'
(ทดสอบแล้วใช้งานได้กับ SQL-Server และ PostgreSQL และระบบ RDBMS อื่น ๆ ทั้งหมดที่รองรับ 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
)ฟังดูซับซ้อน? หากคุณต้องการคุณสมบัติบางอย่างเช่นการละเว้นองค์ประกอบบางอย่างจากการไฮไลต์การแมปไดอะคริติกการแมปคำพ้องความหมายการค้นหาภายใน iframe การค้นหาคำที่แยกจากกัน ฯลฯ สิ่งนี้จะซับซ้อนมากขึ้นเรื่อย ๆ
เมื่อใช้ปลั๊กอินที่มีอยู่และใช้งานได้ดีคุณไม่ต้องกังวลกับสิ่งที่มีชื่อข้างต้น บทความ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";
แปลเป็น CSSstyle="background-color: yellow;"
นั่นคือความแตกต่างเล็กน้อยระหว่าง camelCase และ dashed-notation ทำให้ฉันสะดุดในตอนแรก
นี่คือโซลูชัน regexp pure 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
>
อักขระ แก้ไข regex โดยใช้(?!([^<]+)?<)
เพื่อให้ทำงานได้
ไม่มีวิธีแก้ปัญหาอื่นใดที่ตรงกับความต้องการของฉันเลยและแม้ว่าโซลูชันของ Stefan Steiger จะทำงานได้ตามที่ฉันคาดไว้ แต่ฉันก็พบว่ามันละเอียดเกินไป
ต่อไปนี้เป็นความพยายามของฉัน:
/**
* 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หากคำหลักของคุณสามารถมีอักขระพิเศษที่ต้องใช้ Escape ใน regexes:
const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
ฉันมีปัญหาเดียวกันข้อความจำนวนมากเข้ามาในคำขอ 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 ไว้ในตัวเลือก regexp และจะแทนที่เฉพาะเหตุการณ์แรกเท่านั้น แต่ยังคงเป็นสิ่งที่อยู่ในคุณสมบัติ 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">
หมายเหตุ: ในขณะที่ฉันเห็นด้วยกับ @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>
แท็กเพื่อเน้นข้อความได้ คุณสามารถใช้จาวาสคริปต์เพื่อตัดข้อความ / คำสำคัญระหว่างแท็กเหล่านี้ นี่คือตัวอย่างเล็กน้อยของวิธีการทำเครื่องหมายและยกเลิกการทำเครื่องหมายข้อความ
innerHTML
อันตราย. มันจะลบเหตุการณ์
ก้าวไปข้างหน้าอย่างรวดเร็วในปี 2019 ขณะนี้ Web 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 ()ในประเภทช่วง อาร์กิวเมนต์เดียวคือองค์ประกอบที่จะตัดช่วงนั้น
function styleSelected() {
bg = document.createElement("span");
bg.style.backgroundColor = "yellow";
window.getSelection().getRangeAt(0).surroundContents(bg);
}