如何使用javascript突出显示文本

时间:2011-12-27 12:05:56

标签: javascript highlighting

有人可以帮助我使用可以突出显示网页上文字的javascript功能。 并且要求是 - 只突出一次,而不是像搜索一样突出显示所有出现的文本。

17 个答案:

答案 0 :(得分:76)

您可以使用jquery highlight effect

但如果您对原始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

答案 1 :(得分:33)

这里提供的解决方案非常糟糕。

  1. 您不能使用正则表达式,因为这样,您可以在html标记中搜索/突出显示。
  2. 您不能使用正则表达式,因为它无法正常使用UTF *(任何非拉丁/英文字符)。
  3. 你不能只做一个innerHTML.replace,因为当字符有一个特殊的HTML表示法时,这不起作用,例如: &amp;代表&amp;,&lt;代表&lt;,&gt;代表&gt;,&auml;代表ä,&ouml;代表&uuml;代表ü{{ {1}}用于ß等。
  4. 您需要做什么:

    循环浏览HTML文档,查找所有文本节点,获取&szlig;,使用textContent获取突出显示文本的位置(如果情况属实,则选择indexOf - 不敏感),将toLowerCase之前的所有内容附加为indexof,将匹配的文本附加高亮区域,然后对文本节点的其余部分重复(高亮字符串可能会在{{1}中多次出现) } string)。

    以下是此代码:

    textNode

    然后你可以像这样使用它:

    textContent

    这是一个示例HTML文档

    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); } 在数据库中搜索, 例如<!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&auml;&ouml;&uuml;&Auml;&Ouml;&Uuml;</span> </div> </body> </html> [你不应该这样做,你应该使用全文搜索或Lucene],然后你可以使用\来转义每个字符并添加一个SQL-escape语句,你可以找到特殊字符LIKE表达式。

    e.g。

    LIKE

    并且@query的值不是WHERE textField LIKE CONCAT('%', @query, '%')而是WHERE textField LIKE CONCAT('%', @query, '%') ESCAPE '\'

    (已测试,适用于SQL-Server和PostgreSQL,以及支持ESCAPE的所有其他RDBMS系统)

    修订后的打字稿版本:

    '%completed%'

    用法:

    '%\c\o\m\p\l\e\t\e\d%'

答案 2 :(得分:28)

为什么使用自制高亮功能是一个坏主意

从头开始构建自己的突出显示功能可能是一个坏主意的原因是因为你肯定会遇到其他人已经解决的问题。挑战:

  • 您需要删除包含HTML元素的文本节点,以突出显示您的匹配,而不会破坏DOM事件并反复触发DOM重新生成(例如innerHTML就是这种情况)
  • 如果要删除突出显示的元素,则必须删除包含其内容的HTML元素,并且还必须组合拆分的文本节点以进行进一步搜索。这是必要的,因为每个荧光笔插件都会在文本节点内搜索匹配项,如果您的关键字将被拆分为多个文本节点,则无法找到它们。
  • 您还需要构建测试以确保您的插件能够在您没有考虑过的情况下工作。我正在谈论跨浏览器测试!

听起来很复杂?如果你想要一些功能,比如忽略突出显示,变音符号映射,同义词映射,iframe内搜索,分离词搜索等一些元素,这就变得越来越复杂。

使用现有插件

使用现有的,实施良好的插件时,您不必担心上面提到的内容。 Sitepoint上的文章 10 jQuery text highlighter plugins 比较了流行的荧光笔插件。

查看mark.js

mark.js是一个用纯JavaScript编写的插件,但也可以作为jQuery插件使用。它的开发目的是提供比其他插件更多的机会,可以选择:

  • 分别搜索关键字而不是完整的字词
  • map diacritics(例如,如果“justo”也应匹配“justò”)
  • 忽略自定义元素内的匹配
  • 使用自定义突出显示元素
  • 使用自定义突出显示类
  • 映射自定义同义词
  • 也在iframe内搜索
  • 收到未找到的条款

<强> DEMO

或者,您可以看到this fiddle

使用示例

// Highlight "keyword" in the specified context
$(".context").mark("keyword");

// Highlight the custom regular expression in the specified context
$(".context").markRegExp(/Lorem/gmi);

它是免费的,并在GitHub(project reference)上开发了开源。

答案 3 :(得分:9)

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);
}

答案 4 :(得分:4)

简单的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));
        }
    }
}

然后构建实际结果:

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;
        }
    }
}

答案 5 :(得分:4)

这是我的正则表达式纯JavaScript解决方案:

function highlight(text) {
    document.body.innerHTML = document.body.innerHTML.replace(
        new RegExp(text + '(?!([^<]+)?<)', 'gi'),
        '<b style="background-color:#ff0;font-size:100%">$&</b>'
    );
}

答案 6 :(得分:4)

我有同样的问题,一堆文本通过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>")

要回答你的问题:你可以在regexp选项中省略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>");
});

答案 7 :(得分:2)

其他解决方案都不能满足我的需求,虽然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之类的内容:

const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);

答案 8 :(得分:1)

自HTML5起,您可以使用<mark></mark>标记突出显示文字。您可以使用javascript在这些标记之间包含一些文本/关键字。这是一个如何标记和取消标记文本的小例子。

JSFIDDLE DEMO

答案 9 :(得分:1)

我发现highlight插件是最佳匹配,您可以突出显示部分内容

  。

$( '礼')突出( 'BLA');

答案 10 :(得分:1)

我也想知道,你可以尝试我在this帖子上学到的东西。

我用过:

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

答案 11 :(得分:1)

如果您还希望页面加载时突出显示它,则有一种新方法。

只需添加#:~:text=Highlight%20These

尝试访问此链接

https://stackoverflow.com/questions/38588721#:~:text=Highlight%20a%20text

答案 12 :(得分:1)

只需将您的话传递给以下函数

function highlight_words(word) {
    const page = document.body.innerHTML;
    document.body.innerHTML = page.replace(new RegExp(word, "gi"), (match) => `<mark>${match}</mark>`);
}

用法

highlight_words("hello")

这将突出显示页面上单词的所有实例。

答案 13 :(得分:0)

快进到2019年,Web API现在已本地支持突出显示文本:

const selection = document.getSelection();
selection.setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset);

你很好! anchorNode是选择开始节点,focusNode是选择结束节点。并且,如果它们是文本节点,则offset是相应节点中起始字符和结束字符的索引。这是documentation

他们甚至有一个live demo

答案 14 :(得分:0)

我想分享更多关于scroll text fragment的用法

语法:#:~:text=[prefix-,]textStart[,textEnd][,-suffix]

<头>
示例 演示链接
#:~:text=to How to highlight text using javascript
#:~:text=to,text How to highlight text using javascript
#:~:text=tex-,t How to highlight text using javascript
#:~:text=text-,using,-javascript How to highlight text using javascript

如果您想在一个网址 (&text=) 中突出显示多个文本片段

<头>
示例 演示链接
#:~:text=javascript&text=highlight&text=Ankit How to highlight text using javascript

查看更多:https://web.dev/text-fragments/#textstart

答案 15 :(得分:0)

如果您将标记标签内的任何文本括起来,浏览器将自动以这种醒目的黄色突出显示该文本。 详情请见:https://dev.to/comscience/highlight-searched-text-on-a-page-with-just-javascript-17b3

 <h1>
  Searching and Marking
</h1>

<input type="text" id="search"/>
<button onClick="search(id)" id="button">
Highlight
</button>

<p id="text">
What exactly is this Worker thread module, and why do we need it? In this post, we will talk about the historical reasons concurrency is implemented in JavaScript and Node.js, the problems we might find, current solutions, and the future of parallel processing with Worker threads.

Living in a single-threaded world
JavaScript was conceived as a single-threaded programming language that ran in a browser. Being single-threaded means that only one set of instructions is executed at any time in the same process (the browser, in this case, or just the current tab in modern browsers).

This made things easier for implementation and for developers using the language. JavaScript was initially a language only useful for adding some interaction to webpages, form validations, and so on — nothing that required the complexity of multithreading.
</p>

现在JS代码看起来像这样

function search(e) {
    let searched = document.getElementById("search").value.trim();
  if (searched !== "") {
    let text = document.getElementById("text").innerHTML;
    let re = new RegExp(searched,"g"); // search for all instances
        let newText = text.replace(re, `<mark>${searched}</mark>`);
        document.getElementById("text").innerHTML = newText;
  }
}

答案 16 :(得分:-1)

surroundContents()类型上使用Range方法。它唯一的参数是一个将包装该Range的元素。

function styleSelected() {
  bg = document.createElement("span");
  bg.style.backgroundColor = "yellow";
  window.getSelection().getRangeAt(0).surroundContents(bg);
}