如何使用JavaScript突出显示文本
有人可以帮助我一个JavaScriptfunction,可以突出显示网页上的文字。 要求是 – 只突出显示一次,而不是像在search的情况下突出显示文本的所有出现。
你可以使用jQuery的高亮效果 。
但是,如果您对原始JavaScript代码感兴趣,请查看我所获得的内容。只需将复制粘贴到HTML中,打开文件并单击“突出显示” – 应突出显示“fox”一词。 性能明智,我认为这将做小文本和一个单一的重复(就像你指定)
<script> function highlight(text) { 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; } } </script> <button onclick="highlight('fox')">Highlight</button> <style> .highlight { background-color:yellow; } </style> <div id="inputText"> The fox went over the fence </div>
编辑:
使用replace
我看到这个答案获得了一些人气,我想我可以补充一点。 您也可以轻松使用replace
"the fox jumped over the fence".replace(/fox/,"<span>fox</span>");
或者对于多个事件(与问题无关,但在评论中被问到),您只需在replace正则expression式中添加global
。
"the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");
希望这对有趣的评论者有帮助。
将HTMLreplace为整个网页
要replace整个网页的HTML,你应该引用文档正文的innerHTML
。
document.body.innerHTML
这里提供的解决scheme非常糟糕。
- 你不能使用正则expression式,因为这样,你在html标签中search/突出显示。
- 你不能使用正则expression式,因为它不能正确使用UTF *(任何非拉丁/英文字符)。
- 你不能只是做一个innerHTML.replace,因为当字符有一个特殊的HTML符号时,这不起作用,例如
ä
对于ä,ö
为öü
为üß
对于ß等
你需要做什么:
循环浏览HTML文档,find所有文本节点,获取textContent
,使用indexOf
获取高亮文本的位置(如果应该不区分大小写,则使用可选的toLowerCase
),将indexof
之前的所有内容追加为textNode
,追加匹配的Text使用高亮度范围,并重复其余的textnode(高亮string可能会在textContent
string中出现多次)。
这里是这个代码:
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
在数据库中search,
例如WHERE textField LIKE CONCAT('%', @query, '%')
[你不应该这样做,你应该使用fulltext-search或者Lucene],然后你可以用\转义每个字符,并且添加一个SQL-escape-语句,你会发现LIKEexpression式的特殊字符。
例如
WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'
并且@query的值不是'% completed'
而是'\%\ \c\o\m\p\l\e\t\e\d'
(经testing,适用于SQL-Server和PostgreSQL,以及其他支持ESCAPE的RDBMS系统)
为什么使用自制的突出显示function是一个坏主意
从零开始构build自己的突出显示function可能是一个糟糕的主意,因为您肯定会遇到其他人已经解决的问题。 挑战:
- 您将需要使用HTML元素删除文本节点,以突出显示您的匹配,而不会破坏DOM事件并一次又一次地触发DOM重新生成(例如,对于如
innerHTML
) - 如果你想删除突出显示的元素,你将不得不删除HTML元素与他们的内容,也必须结合拆分文本节点进一步search。 这是必要的,因为每个荧光笔插件search文本节点内匹配,如果您的关键字将被拆分成几个文本节点,他们将不会被发现。
- 您还需要构buildtesting以确保您的插件能够在您没有想到的情况下工作。 而我正在谈论跨浏览器testing!
听起来很复杂? 如果您想要某些function忽略突出显示的某些元素,变音符映射,同义词映射,内部iframesearch,分词search等,这变得越来越复杂。
使用现有的插件
当使用现有的,很好实施的插件,你不必担心上述命名的事情。 第10条jQuery文字荧光笔插件 Sitepoint比较stream行的荧光笔插件。
看看mark.js
mark.js是一个用纯JavaScript编写的插件,也可以作为jQuery插件使用。 它的开发提供了更多的机会比其他插件与选项:
- 单独search关键字而不是完整的术语
- 地图变音符号(例如,如果“justo”也应该匹配“justò”)
- 忽略自定义元素内的匹配
- 使用自定义高亮元素
- 使用自定义高亮类
- 映射自定义同义词
- 也search内部框架
- 收不到条款
DEMO
或者你可以看到这个小提琴 。
用法示例 :
// 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() { //alert(text.focusOffset - text.anchorOffset); var text = window.getSelection(); var start = text.anchorOffset; alert(start); var end = text.focusOffset - text.anchorOffset; alert(end); range = window.getSelection().getRangeAt(0); range1 = window.getSelection().toString(); var selectionContents = range.extractContents(); var span = document.createElement("span"); span.appendChild(selectionContents); span.setAttribute("class", "uiWebviewHighlight"); 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>'
问题是我不需要突出显示标签中的文本。 例如,我需要突出显示狐狸:
现在我可以用它来replace它:
var word="fox"; word="(\\b"+ word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1") + "\\b)"; var r = new RegExp(word,"igm"); str.replace(r,"<span class='hl'>$1</span>")
要回答你的问题:你可以在正则expression式选项中省略g,只有第一次出现才会被replace,但是这仍然是img src属性中的一个,并且销毁了image标签:
<img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span class='hl'>fox</span> />
这是我解决它的方式,但想知道是否有更好的方法,我在正则expression式中错过了:
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>"); });
简单的TypeScript示例
注意:虽然我很同意@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)); } } }
然后构build实际的结果:
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; } } }
我发现高亮插件是最好的搭配,它可以突出显示部分内容 :
$( '礼')亮点(以 '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="http://img.dovov.comcomment_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>
这是我的正则expression式纯JavaScript解决scheme:
function highlight(text) { document.body.innerHTML = document.body.innerHTML.replace( new RegExp(text + '(?!([^<]+)?<)', 'gi'), '<b style="background-color:#ff0;font-size:100%">$&</b>' ); }
自HTML5以来,您可以使用<mark></mark>
标记来突出显示文本。 您可以使用JavaScript来包装这些标签之间的文字/关键字。 这里是一个如何标记和取消标记文本的例子。
JSFIDDLE DEMO
使用Rangetypes的surroundContents()方法。 它唯一的参数是一个将包裹该范围的元素。
function styleSelected() { bg = document.createElement("span"); bg.style.backgroundColor = "yellow"; window.getSelection().getRangeAt(0).surroundContents(bg); }