2010-10-11 68 views
1

我有一个页面,我在一个div中显示一些文本,我需要在某些部分突出显示此文本。我通过围绕我需要使用标记和适当的css样式来突出显示的文本来完成此操作。 例如 <div> My text will look like this with <span class="highlight">highlighted bits</span> in it. </div>如何突出显示用户在已经突出显示的文本内选择的文本?

这工作正常。但是,此页面的另一个要求是用户必须能够选择文本,单击按钮,并且所选文本也必须高亮显示。

我遇到的问题是,当试图确定选择的文本的范围来抓取(使用window.getSelection.getRangeAt(0)),这给了我的范围,重置每个<span>标签在文本中,而不是文本的开始。

回答

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

那太好了,你能不能给一些洞察到什么呢每个代码位,并显示使用中的这个例子(jsfiddle,codepen,你喜欢什么)? 关键点的小解释将不胜感激。 – Deviljho 2014-11-27 17:37:59