【问题标题】:how to highlight user selected text within a piece of text which has already been highlighted?如何在已经突出显示的一段文本中突出显示用户选择的文本?
【发布时间】:2011-04-23 16:40:48
【问题描述】:

我有一个页面,我在 div 中显示一些文本,我需要在某些部分突出显示该文本。我通过使用标签和适当的 css 样式包围我需要突出显示的文本来做到这一点。 例如。 <div> My text will look like this with <span class="highlight">highlighted bits</span> in it. </div>

这很好用。但是,此页面的另一个要求是用户必须能够选择文本、单击按钮,并且所选文本也必须突出显示。

我遇到的问题是在尝试识别要抓取的选定文本的范围时(使用 window.getSelection.getRangeAt(0)),这给了我在文本中的每个 &lt;span&gt; 标记后重置的范围,而不是从正文开始。

【问题讨论】:

    标签: select text highlight


    【解决方案1】:

    对于那些想知道未来的人,我就是这样做的:

    jQuery.fn.highlight = function(startOffset,endOffset,type) {
     function innerHighlight(node, startOffset,endOffset) {
         var calledStartOffset = parseInt(startOffset);
         var startOffsetNode=getChildNodeForOffset(node,parseInt(startOffset));
         var endOffsetNode=getChildNodeForOffset(node,parseInt(endOffset));
         startOffset = resizeOffsetForNode(startOffsetNode,parseInt(startOffset));
    
         if (startOffsetNode == endOffsetNode){
             endOffset = resizeOffsetForNode(endOffsetNode,parseInt(endOffset));
             highlightSameNode(startOffsetNode, parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
         } else {
             highlightDifferentNode(startOffsetNode,endOffsetNode,parseInt(startOffset),parseInt(endOffset),type,calledStartOffset);
         }
     }
     return this.each(function() {
         innerHighlight(this, startOffset,endOffset);
     });
    };
    
    function resizeOffsetForNode(offsetNode,offset){
     if (offsetNode.id >= 0){
         offset = parseInt(offset)-parseInt(offsetNode.id);
     } else if (offsetNode.previousSibling != null && offsetNode.previousSibling.id > 0){
         offset = parseInt(offset)-parseInt(offsetNode.previousSibling.id)-parseInt(offsetNode.previousSibling.textContent.length);
     }  
     return offset;
    }
    
    function getChildNodeForOffset(testNode,offset) {
        if (testNode.nodeType == 1 && testNode.childNodes && !/(script|style)/i.test(testNode.tagName)) {
           var offsetNode=null;
           var currentNode;
           for (var i = 0; i < testNode.childNodes.length; ++i) {
               currentNode=testNode.childNodes[i];
               if (currentNode.id >= 0 && parseInt(currentNode.id) <= parseInt(offset) && ((parseInt(currentNode.id) + parseInt(currentNode.textContent.length)) >= parseInt(offset))){
                   offsetNode = currentNode;
                   break;
               } else if (currentNode.id >= 0 && parseInt(currentNode.id) > parseInt(offset)){
                   offsetNode = currentNode.previousSibling;
                   break;
               }
            }
           if (offsetNode==null){
               offsetNode = testNode.childNodes[testNode.childNodes.length-1]; 
           }
           return offsetNode;
        }
    }
    
    function highlightSameNode(node, startOffset,endOffset,type,calledStartOffset) {
       var skip = 0;
       if (node.nodeType == 3) {
       if (startOffset >= 0) {
        var spannode = document.createElement('span');
        spannode.className = 'entity '+ type;
        spannode.id=calledStartOffset;
        var middlebit = node.splitText(startOffset);
        var endbit = middlebit.splitText(endOffset-startOffset);
        var middleclone = middlebit.cloneNode(true);
        spannode.appendChild(middleclone);
        middlebit.parentNode.replaceChild(spannode, middlebit);
       }
      } else if (node.nodeType == 1 && node.childNodes && !/(script|style)/i.test(node.tagName)) {
        var childnode = node.childNodes[0];
        highlightSameNode(childnode, startOffset,endOffset,type,calledStartOffset);
      }
    }
    
    function highlightDifferentNode(startnode, endnode, startOffset,endOffset,type,calledStartOffset) {
       var skip = 0;
       if (startnode.nodeName == "#text") {
           if (startOffset >= 0) {
                var spannode = document.createElement('span');
                spannode.className = 'entity '+ type;
                spannode.id=calledStartOffset;
                var endbit = node.splitText(startOffset);
                var endclone = endbit.cloneNode(true);
                spannode.appendChild(endclone);
                endbit.parentNode.replaceChild(spannode, endbit);
           }
       } else if (startnode.nodeName == "SPAN") {
           if (startOffset >= 0) {
                var spannode = document.createElement('span');
                spannode.className = 'entity '+ type;
                spannode.id=calledStartOffset;
                var endTextbit = startnode.childNodes[0].splitText(startOffset);
                spannode.appendChild(endTextbit);
                startnode.parentNode.insertBefore(spannode, startnode.nextSibling);
           }
       }
       var currentTestNode=startnode.nextSibling;
       while (currentTestNode!=endnode){
           if (currentTestNode.nodeName == "#text") {
                var spannode = document.createElement('span');
                spannode.className = 'entity '+ type;
                spannode.id=parseInt(currentTestNode.previousSibling.id)+parseInt(currentTestNode.previousSibling.textContent.length);
                var currentNodeClone=currentTestNode.cloneNode(true);
                spannode.appendChild(currentNodeClone);
                endbit.parentNode.replaceChild(spannode, currentTestNode);
           } else if (currentTestNode.nodeName == "SPAN") {
                currentTestNode.className = 'entity overlap';
           }
           currentTestNode=currentTestNode.nextSibling;
       }
       var previousNodeEnd = parseInt(endnode.previousSibling.id)+parseInt(endnode.previousSibling.textContent.length);
       var spannode = document.createElement('span');
       spannode.className = 'entity '+ type;
       spannode.id=previousNodeEnd;
       if (endnode.nodeName == "#text") {
           if (endOffset >= 0) {
                //end offset here is the original end offset from the beginning of the text, not node
                var unwantedbit = endnode.splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
                var endclone = endnode.cloneNode(true);
                spannode.appendChild(endclone);
                endnode.parentNode.replaceChild(spannode, endnode);
           }
       } else if (endnode.nodeName == "SPAN") {
           if (endOffset >= 0) {
                var wantTextbit = endnode.childNodes[0].splitText(parseInt(endOffset)-parseInt(previousNodeEnd));
                spannode.appendChild(wantTextbit);
                wantTextbit.parentNode.parentNode.insertBefore(spannode, endnode);
           }
       }
       if (startnode.textContent.length < 1){
        startnode.parentNode.removeChild(startnode);
       }
       if (endnode.textContent.length < 1){
           endnode.parentNode.removeChild(endnode);
       }
    }
    
    jQuery.fn.removeHighlight = function() {
     return this.find("span.entity").each(function() {
      this.parentNode.firstChild.nodeName;
      with (this.parentNode) {
       replaceChild(this.firstChild, this);
       normalize();
      }
     }).end();
    };
    
    function contains(a, b){
          return a.contains ? a != b && a.contains(b) : !!(a.compareDocumentPosition(b) & 16);
    } 
    

    【讨论】:

    • 太好了,您能否深入了解每一段代码的作用,并展示一个使用中的示例(jsfiddle、codepen,无论您喜欢什么)?对关键点的小解释将不胜感激。
    猜你喜欢
    • 2010-10-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-23
    • 2012-07-27
    相关资源
    最近更新 更多