How to highlight text using javascript

后端 未结 13 2255
名媛妹妹
名媛妹妹 2020-11-22 02:32

Can someone help me with a javascript function that can highlight text on a web page. And the requirement is to - highlight only once, not like highlight all occurrences of

相关标签:
13条回答
  • 2020-11-22 02:54

    I have the same problem, a bunch of text comes in through a xmlhttp request. This text is html formatted. I need to highlight every occurrence.

    str='<img src="brown fox.jpg" title="The brown fox" />'
        +'<p>some text containing fox.</p>'
    

    The problem is that I don't need to highlight text in tags. For example I need to highlight fox:

    Now I can replace it with:

    var word="fox";
    word="(\\b"+ 
        word.replace(/([{}()[\]\\.?*+^$|=!:~-])/g, "\\$1")
            + "\\b)";
    var r = new RegExp(word,"igm");
    str.replace(r,"<span class='hl'>$1</span>")
    

    To answer your question: you can leave out the g in regexp options and only first occurrence will be replaced but this is still the one in the img src property and destroys the image tag:

    <img src="brown <span class='hl'>fox</span>.jpg" title="The brown <span 
    class='hl'>fox</span> />
    

    This is the way I solved it but was wondering if there is a better way, something I've missed in regular expressions:

    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>");
    });
    
    0 讨论(0)
  • 2020-11-22 02:55

    You can use the jquery highlight effect.

    But if you are interested in raw javascript code, take a look at what I got Simply copy paste into an HTML, open the file and click "highlight" - this should highlight the word "fox". Performance wise I think this would do for small text and a single repetition (like you specified)

    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>

    Edits:

    Using replace

    I see this answer gained some popularity, I thought I might add on it. You can also easily use replace

    "the fox jumped over the fence".replace(/fox/,"<span>fox</span>");

    Or for multiple occurrences (not relevant for the question, but was asked in comments) you simply add global on the replace regular expression.

    "the fox jumped over the other fox".replace(/fox/g,"<span>fox</span>");

    Hope this helps to the intrigued commenters.

    Replacing the HTML to the entire web-page

    to replace the HTML for an entire web-page, you should refer to innerHTML of the document's body.

    document.body.innerHTML

    0 讨论(0)
  • 2020-11-22 02:55

    Why using a selfmade highlighting function is a bad idea

    The reason why it's probably a bad idea to start building your own highlighting function from scratch is because you will certainly run into issues that others have already solved. Challenges:

    • You would need to remove text nodes with HTML elements to highlight your matches without destroying DOM events and triggering DOM regeneration over and over again (which would be the case with e.g. innerHTML)
    • If you want to remove highlighted elements you would have to remove HTML elements with their content and also have to combine the splitted text-nodes for further searches. This is necessary because every highlighter plugin searches inside text nodes for matches and if your keywords will be splitted into several text nodes they will not being found.
    • You would also need to build tests to make sure your plugin works in situations which you have not thought about. And I'm talking about cross-browser tests!

    Sounds complicated? If you want some features like ignoring some elements from highlighting, diacritics mapping, synonyms mapping, search inside iframes, separated word search, etc. this becomes more and more complicated.

    Use an existing plugin

    When using an existing, well implemented plugin, you don't have to worry about above named things. The article 10 jQuery text highlighter plugins on Sitepoint compares popular highlighter plugins.

    Have a look at mark.js

    mark.js is such a plugin that is written in pure JavaScript, but is also available as jQuery plugin. It was developed to offer more opportunities than the other plugins with options to:

    • search for keywords separately instead of the complete term
    • map diacritics (For example if "justo" should also match "justò")
    • ignore matches inside custom elements
    • use custom highlighting element
    • use custom highlighting class
    • map custom synonyms
    • search also inside iframes
    • receive not found terms

    DEMO

    Alternatively you can see this fiddle.

    Usage example:

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

    It's free and developed open-source on GitHub (project reference).

    0 讨论(0)
  • 2020-11-22 02:56

    None of the other solutions really fit my needs, and although Stefan Steiger's solution worked as I expected I found it a bit too verbose.

    Following is my attempt:

    /**
     * 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>

    I would also recommend using something like escape-string-regexp if your keywords can have special characters that would need to be escaped in regexes:

    const keywordRegex = RegExp(keywords.map(escapeRegexp).join('|')), flags);
    
    0 讨论(0)
  • 2020-11-22 02:56

    Since HTML5 you can use the <mark></mark> tags to highlight text. You can use javascript to wrap some text/keyword between these tags. Here is a little example of how to mark and unmark text.

    JSFIDDLE DEMO

    0 讨论(0)
  • 2020-11-22 02:57

    I was wondering that too, you could try what I learned on this post.

    I used:

    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>

    you could also try it here: http://henriquedonati.com/projects/Extension/extension.html

    xc

    0 讨论(0)
提交回复
热议问题