有人可以帮助我使用可以突出显示网页上的文本的 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
替换正则表达式。
"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");
希望这对感兴趣的评论者有所帮助。
将 HTML 替换为整个网页
要替换整个网页的 HTML,您应该参考innerHTML
文档正文的 。
document.body.innerHTML
这里提供的解决方案非常糟糕。
- 您不能使用正则表达式,因为那样,您可以在 html 标签中搜索/突出显示。
- 您不能使用正则表达式,因为它不能与 UTF*(任何非拉丁文/英文字符)一起正常工作。
- 你不能只做一个innerHTML.replace,因为当字符有特殊的HTML符号时这不起作用,例如
&
&、<
<、>
>、ä
ä、ö
öü
、üß
、ß等。
你需要做什么:
循环遍历 HTML 文档,找到所有文本节点,获取textContent
,获取突出显示文本的位置indexOf
(toLowerCase
如果不区分大小写,则为可选),将所有内容附加在indexof
as之前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 转义语句,这样你会发现 LIKE 表达式的特殊字符。
例如
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
而@query 的值不是'%completed%'
但是'%\c\o\m\p\l\e\t\e\d%'
(经过测试,适用于 SQL-Server 和 PostgreSQL,以及所有其他支持 ESCAPE 的 RDBMS 系统)
修改后的typescript版本:
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 元素及其内容,并且还必须组合拆分的文本节点以进行进一步搜索。这是必要的,因为每个荧光笔插件都会在文本节点内搜索匹配项,并且如果您的关键字将被拆分为多个文本节点,它们将不会被找到。
- 您还需要构建测试以确保您的插件在您没有考虑过的情况下工作。我说的是跨浏览器测试!
听起来很复杂?如果您想要一些功能,例如从突出显示、变音符号映射、同义词映射、iframe 内搜索、分离词搜索等中忽略某些元素,这将变得越来越复杂。
使用现有插件
使用现有的、实现良好的插件时,您不必担心上述命名的事情。Sitepoint 上的文章10 jQuery 文本荧光笔插件比较了流行的荧光笔插件。
看看mark.js
mark.js就是这样一个用纯 JavaScript 编写的插件,但也可以作为 jQuery 插件使用。它的开发目的是提供比其他插件更多的机会,可以选择:
- 单独搜索关键字而不是完整的术语
- 映射变音符号(例如,如果“justo”也应该匹配“justò”)
- 忽略自定义元素内的匹配项
- 使用自定义高亮元素
- 使用自定义突出显示类
- 映射自定义同义词
- 也在 iframe 内搜索
- 收到未找到的条款
或者你可以看到这个 fiddle。
用法示例:
// 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);
}
这是我的正则表达式纯 JavaScript 解决方案:
function highlight(text) {
document.body.innerHTML = document.body.innerHTML.replace(
new RegExp(text + '(?!([^<]+)?<)', 'gi'),
'<b style="background-color:#ff0;font-size:100%">$&</b>'
);
}