Javascript selected text highlighting prob

后端 未结 6 602
名媛妹妹
名媛妹妹 2021-01-31 05:14

I have a html page with text content. On selecting any text and pressing the highlight button, I can change the style of the selected text to highlight the same. To implement th

相关标签:
6条回答
  • 2021-01-31 05:18

    Rather than reinvent the wheel, I'd use Rangy's highlighting capabilities.

    I've forked the fiddle that RGraham created and created a new fiddle that shows how it works. This is how it is done:

    var applier = rangy.createClassApplier("highlight");
    var highlighter = rangy.createHighlighter();
    highlighter.addClassApplier(applier);
    
    document.getElementById('execute').addEventListener('click', function() {
        highlighter.removeAllHighlights();
        highlighter.highlightSelection("highlight");
    });
    

    What this does is create a highlighter that will set the highlight class on elements that are wholly inside the selection, and create spans with the highlight class as needed for elements that straddle the selection. When the button with the id execute is clicked, the old highlights are removed and the new highlights applied.

    The highlighter functionality is part of release of Rangy that are considered to be "alpha". However, I've been consistently using alpha releases of Rangy for a few years now but it has been extremely rare that I found a problem with my application that I could trace back to Rangy. And the few times I found a problem with Rangy, Tim Down (its author) was quite responsive.

    0 讨论(0)
  • 2021-01-31 05:22

    See Range.extractContents:

    document.getElementById('execute').addEventListener('click', function() {
        var range = window.getSelection().getRangeAt(0),
            span = document.createElement('span');
    
        span.className = 'highlight';
        span.appendChild(range.extractContents());
        range.insertNode(span);
    });
    .highlight { background-color: yellow; }
    <div id="test">
        Select any part of <b>this text and</b> then click 'Run'.
    </div>
    
    <button id="execute">Run</button>

    0 讨论(0)
  • 2021-01-31 05:38

    The solution is really tricky. I somehow find a workaround. See my fiddle

    function highlight() {
        var range = window.getSelection().getRangeAt(0),
            parent = range.commonAncestorContainer,
            start = range.startContainer,
            end = range.endContainer;
        var startDOM = (start.parentElement == parent) ? start.nextSibling : start.parentElement;
        var currentDOM = startDOM.nextElementSibling;
        var endDOM = (end.parentElement == parent) ? end : end.parentElement;
        //Process Start Element
        highlightText(startDOM, 'START', range.startOffset);
        while (currentDOM != endDOM && currentDOM != null) {
            highlightText(currentDOM);
            currentDOM = currentDOM.nextElementSibling;
        }
        //Process End Element
        highlightText(endDOM, 'END', range.endOffset);
    }
    
    function highlightText(elem, offsetType, idx) {
        if (elem.nodeType == 3) {
            var span = document.createElement('span');
            span.setAttribute('class', 'highlight');
            var origText = elem.textContent, text, prevText, nextText;
            if (offsetType == 'START') {
                text = origText.substring(idx);
                prevText = origText.substring(0, idx);
            } else if (offsetType == 'END') {
                text = origText.substring(0, idx);
                nextText = origText.substring(idx);
            } else {
                text = origText;
            }
            span.textContent = text;
    
            var parent = elem.parentElement;
            parent.replaceChild(span, elem);
            if (prevText) { 
                var prevDOM = document.createTextNode(prevText);
                parent.insertBefore(prevDOM, span);
            }
            if (nextText) {
                var nextDOM = document.createTextNode(nextText);
                parent.appendChild(nextDOM);
            }
            return;
        }
        var childCount = elem.childNodes.length;
        for (var i = 0; i < childCount; i++) {
            if (offsetType == 'START' && i == 0) 
                highlightText(elem.childNodes[i], 'START', idx);
            else if (offsetType == 'END' && i == childCount - 1)
                highlightText(elem.childNodes[i], 'END', idx);
            else
                highlightText(elem.childNodes[i]);
        }
    }
    
    0 讨论(0)
  • 2021-01-31 05:39
    if (window.getSelection) {
                    var sel = window.getSelection();
                    if (!sel) {
                        return;
                    }
                    var range = sel.getRangeAt(0);
                    var start = range.startContainer;
                    var end = range.endContainer;
                    var commonAncestor = range.commonAncestorContainer;
                    var nodes = [];
                    var node;
    
                    for (node = start.parentNode; node; node = node.parentNode){
                       var tempStr=node.nodeValue;
                       if(node.nodeValue!=null &&    tempStr.replace(/^\s+|\s+$/gm,'')!='')
                         nodes.push(node);
                       if (node == commonAncestor)
                         break;
                    }
                    nodes.reverse();
    
                    for (node = start; node; node = getNextNode(node)){
                       var tempStr=node.nodeValue;
                       if(node.nodeValue!=null &&  tempStr.replace(/^\s+|\s+$/gm,'')!='')
                         nodes.push(node);
                       if (node == end)
                        break;
                    }
    
                    for(var i=0 ; i<nodes.length ; i++){
    
                       var sp1 = document.createElement("span");
                       sp1.setAttribute("class", "highlight"+color );
                       var sp1_content = document.createTextNode(nodes[i].nodeValue);
                       sp1.appendChild(sp1_content);
                       var parentNode = nodes[i].parentNode;
                       parentNode.replaceChild(sp1, nodes[i]);
                    }
               }
    
    0 讨论(0)
  • 2021-01-31 05:40

    try this:

    newNode.appendChild(range.extractContents())
    

    according to MDN:

    Partially selected nodes are cloned to include the parent tags necessary to make the document fragment valid.

    Whereas Range.surroundContents:

    An exception will be thrown, however, if the Range splits a non-Text node with only one of its boundary points. That is, unlike the alternative above, if there are partially selected nodes, they will not be cloned and instead the operation will fail.

    Didn't test, but...

    0 讨论(0)
  • 2021-01-31 05:43

    This solution is bit tricky, but I find it would be sufficient

    When you will see closely in selection object that we get through calling

    window.getSelection().getRangeAt(0)
    

    You will se that there are 4 properties: startContainer, startOffset, endContainer, endOffset.

    So now you need to start with startContainer with startOffset and start putting your necessary span nodes from there.

    If now it endContainer is different node then you need to start traversing nodes from startContainer to endContainer

    For traversing you need to check for child nodes and sibling nodes which you can get from DOM objects. So first go through startContainer, go through all its child and check if child node is inline element then apply span tag around it, and then you need to write few coding for various corner cases.

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