2008-11-20 49 views
14

我试图找到一种JavaScript的方式来突出显示用户选择的文本,当他们点击一些奇怪的突出显示按钮(如< span style =“background-color:yellow”>突出显示的文本< /范围>)。它只有与任何WebKit的或Firefox的工作,但它似乎是几乎不可能,因为它在下列情况下工作:javascript用户选择突出

<p>this is text</p> 
<p>I eat food</p> 

当用户从“是文本”通过选择“我吃”在浏览器中(不能只是放在那里)。

这种情况:

<span><span>this is text</span>middle text<span>this is text</span></span> 

当用户从选择了“是文本”到“这是”在浏览器中(即使你可以用你的亮点跨越各个元件周围的选择,我d喜欢看到你试图让中间文字突出显示)。

这个问题似乎没有解决任何地方,坦率地说,我怀疑这是可能的。

这将是可能的,如果你可以得到范围,你从选择得到的字符串完整的HTML可以被解析,然后取代,但据我可以告诉你不能得到原始的HTML一个范围..可惜。

回答

4
<html> 
<head> 
<script type="text/javascript"> 
function load(){ 
    window.document.designMode = "On"; 
    //run this in a button, will highlight selected text 
    window.document.execCommand("hiliteColor", false, "#000"); 
} 
</script> 
</head> 
<body contentEditable="true" onload="load()"> 
    this is text 
</body> 
</html> 
+0

这无疑是最好的主意。很好的答案,但是事后再打开`designMode`确实是个好主意。 – 2010-01-11 21:18:51

+0

尽管帖子已经很老了,但我仍然认为这是我现在可以找到的最佳解决方案 – raoulinski 2014-08-28 15:14:38

8

那么,你可以使用DOM操作。这适用于Firefox:

var selection = window.getSelection(); 
var range = selection.getRangeAt(0); 
var newNode = document.createElement("span"); 
newNode.setAttribute("style", "background-color: pink;"); 
range.surroundContents(newNode); 

似乎也适用于当前版本的Safari。请参阅https://developer.mozilla.org/en/DOM/range.surroundContentshttp://www.w3.org/TR/2000/REC-DOM-Level-2-Traversal-Range-20001113/ranges.html

+3

如果选择跨越元素边界(例如,如果它跨越多个段落),则这不起作用。 – 2012-01-05 11:10:03

32

这个答案可能对您来说太晚了,但我面临类似的问题,并希望在此处记录它,因为它是Google上的第一次搜索。

要重申一下,问题是你想只从用户选择拍摄范围对象和环绕它与一个样式的div,像这样:

function highlightSelection() { 
    var userSelection = window.getSelection().getRangeAt(0); 
    highlightRange(userSelection); 

} 

function highlightRange(range) { 
    var newNode = document.createElement("div"); 
    newNode.setAttribute(
     "style", 
     "background-color: yellow; display: inline;" 
    ); 
    range.surroundContents(newNode); 
} 

但作为原始亲本的状态,这是不安全的。如果选择不跨越元素边界,它将起作用,但如果由用户选择创建的范围是跨越HTML标记边界的不安全范围,则会引发DOM错误。


溶液是产生较小的范围内的物体,其中没有一个单独的交叉元件阻挡的阵列,但是其共同覆盖由用户选择的范围。这些安全范围中的每一个都可以像上面那样突出显示。

function getSafeRanges(dangerous) { 
    var a = dangerous.commonAncestorContainer; 
    // Starts -- Work inward from the start, selecting the largest safe range 
    var s = new Array(0), rs = new Array(0); 
    if (dangerous.startContainer != a) 
     for(var i = dangerous.startContainer; i != a; i = i.parentNode) 
      s.push(i) 
    ; 
    if (0 < s.length) for(var i = 0; i < s.length; i++) { 
     var xs = document.createRange(); 
     if (i) { 
      xs.setStartAfter(s[i-1]); 
      xs.setEndAfter(s[i].lastChild); 
     } 
     else { 
      xs.setStart(s[i], dangerous.startOffset); 
      xs.setEndAfter(
       (s[i].nodeType == Node.TEXT_NODE) 
       ? s[i] : s[i].lastChild 
      ); 
     } 
     rs.push(xs); 
    } 

    // Ends -- basically the same code reversed 
    var e = new Array(0), re = new Array(0); 
    if (dangerous.endContainer != a) 
     for(var i = dangerous.endContainer; i != a; i = i.parentNode) 
      e.push(i) 
    ; 
    if (0 < e.length) for(var i = 0; i < e.length; i++) { 
     var xe = document.createRange(); 
     if (i) { 
      xe.setStartBefore(e[i].firstChild); 
      xe.setEndBefore(e[i-1]); 
     } 
     else { 
      xe.setStartBefore(
       (e[i].nodeType == Node.TEXT_NODE) 
       ? e[i] : e[i].firstChild 
      ); 
      xe.setEnd(e[i], dangerous.endOffset); 
     } 
     re.unshift(xe); 
    } 

    // Middle -- the uncaptured middle 
    if ((0 < s.length) && (0 < e.length)) { 
     var xm = document.createRange(); 
     xm.setStartAfter(s[s.length - 1]); 
     xm.setEndBefore(e[e.length - 1]); 
    } 
    else { 
     return [dangerous]; 
    } 

    // Concat 
    rs.push(xm); 
    response = rs.concat(re);  

    // Send to Console 
    return response; 
} 

然后可以对(出现)强调用户选择,这个修改后的代码:

function highlightSelection() { 
    var userSelection = window.getSelection().getRangeAt(0); 
    var safeRanges = getSafeRanges(userSelection); 
    for (var i = 0; i < safeRanges.length; i++) { 
     highlightRange(safeRanges[i]); 
    } 
} 

需要注意的是你“,可能需要一些发烧友CSS使许多用户可以一起看起来不同的元素。我希望最终这可以帮助互联网上的其他疲惫的灵魂!

1

我今天遇到了同样的问题,突出显示了选定的标签,它覆盖了多个标签。 解决办法:

  1. 找到一种方法,与HTML标签沿提取选定部分。
  2. 用span元素包裹提取的部分,并将其放回到DOM中。

请参考下面的代码进一步说明。

function getRangeObject(selectionObject){ 
    try{ 
     if(selectionObject.getRangeAt) 
      return selectionObject.getRangeAt(0); 
    } 
    catch(ex){ 
     console.log(ex); 
    } 
} 
document.onmousedown = function(e){ 
    var text; 
    if (window.getSelection) { 
     /* get the Selection object */ 
     userSelection = window.getSelection() 

     /* get the innerText (without the tags) */ 
     text = userSelection.toString(); 

     /* Creating Range object based on the userSelection object */ 
     var rangeObject = getRangeObject(userSelection); 

     /* 
      This extracts the contents from the DOM literally, inclusive of the tags. 
      The content extracted also disappears from the DOM 
     */ 
     contents = rangeObject.extractContents(); 

     var span = document.createElement("span"); 
     span.className = "highlight"; 
     span.appendChild(contents); 

     /* Insert your new span element in the same position from where the selected text was extracted */ 
     rangeObject.insertNode(span); 

    } else if (document.selection && document.selection.type != "Control") { 
      text = document.selection.createRange().text; 
    } 
}; 
4

这是我第一次在这里发帖,而是通过你的回答看,就不会像这样的工作?我这里有一个例子: http://henriquedonati.com/projects/Extension/extension.html

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

下面是一个完整的代码突出和dehighlight文本

<!DOCTYPE html> 
    <html> 
     <head> 
      <style type="text/css"> 
       .highlight 
       { 
        background-color: yellow; 
       } 
       #test-text::-moz-selection { /* Code for Firefox */ 

        background: yellow; 
       } 

       #test-text::selection { 

        background: yellow; 
       } 

      </style> 
     </head> 

     <body> 
      <div id="div1" style="border: 1px solid #000;"> 
       <div id="test-text"> 
        <h1> Hello How are you </h1> 
        <p > 
         Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum. 
        </p> 
       </div> 
      </div> 
      <br /> 

     </body> 
     <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script> 
      <script type="text/javascript"> 
       mouseXPosition = 0; 
       $(document).ready(function() { 

        $("#test-text").mousedown(function (e1) { 
         mouseXPosition = e1.pageX;//register the mouse down position 
        }); 

        $("#test-text").mouseup(function (e2) { 
         var highlighted = false; 
         var selection = window.getSelection(); 
         var selectedText = selection.toString(); 
         var startPoint = window.getSelection().getRangeAt(0).startOffset; 
         var endPoint = window.getSelection().getRangeAt(0).endOffset; 
         var anchorTag = selection.anchorNode.parentNode; 
         var focusTag = selection.focusNode.parentNode; 
         if ((e2.pageX - mouseXPosition) < 0) { 
          focusTag = selection.anchorNode.parentNode; 
          anchorTag = selection.focusNode.parentNode; 
         } 
         if (selectedText.length === (endPoint - startPoint)) { 
          highlighted = true; 

          if (anchorTag.className !== "highlight") { 
           highlightSelection(); 
          } else { 
           var afterText = selectedText + "<span class = 'highlight'>" + anchorTag.innerHTML.substr(endPoint) + "</span>"; 
           anchorTag.innerHTML = anchorTag.innerHTML.substr(0, startPoint); 
           anchorTag.insertAdjacentHTML('afterend', afterText); 
          } 

         }else{ 
          if(anchorTag.className !== "highlight" && focusTag.className !== "highlight"){ 
           highlightSelection(); 
           highlighted = true; 
          } 

         } 


         if (anchorTag.className === "highlight" && focusTag.className === 'highlight' && !highlighted) { 
          highlighted = true; 

          var afterHtml = anchorTag.innerHTML.substr(startPoint); 
          var outerHtml = selectedText.substr(afterHtml.length, selectedText.length - endPoint - afterHtml.length); 
          var anchorInnerhtml = anchorTag.innerHTML.substr(0, startPoint); 
          var focusInnerHtml = focusTag.innerHTML.substr(endPoint); 
          var focusBeforeHtml = focusTag.innerHTML.substr(0, endPoint); 
          selection.deleteFromDocument(); 
          anchorTag.innerHTML = anchorInnerhtml; 
          focusTag.innerHTml = focusInnerHtml; 
          var anchorafterHtml = afterHtml + outerHtml + focusBeforeHtml; 
          anchorTag.insertAdjacentHTML('afterend', anchorafterHtml); 


         } 

         if (anchorTag.className === "highlight" && !highlighted) { 
          highlighted = true; 
          var Innerhtml = anchorTag.innerHTML.substr(0, startPoint); 
          var afterHtml = anchorTag.innerHTML.substr(startPoint); 
          var outerHtml = selectedText.substr(afterHtml.length, selectedText.length); 
          selection.deleteFromDocument(); 
          anchorTag.innerHTML = Innerhtml; 
          anchorTag.insertAdjacentHTML('afterend', afterHtml + outerHtml); 
         } 

         if (focusTag.className === 'highlight' && !highlighted) { 
          highlighted = true; 
          var beforeHtml = focusTag.innerHTML.substr(0, endPoint); 
          var outerHtml = selectedText.substr(0, selectedText.length - beforeHtml.length); 
          selection.deleteFromDocument(); 
          focusTag.innerHTml = focusTag.innerHTML.substr(endPoint); 
          outerHtml += beforeHtml; 
          focusTag.insertAdjacentHTML('beforebegin', outerHtml); 


         } 
         if (!highlighted) { 
          highlightSelection(); 
         } 
         $('.highlight').each(function(){ 
          if($(this).html() == ''){ 
           $(this).remove(); 
          } 
         }); 
         selection.removeAllRanges(); 
        }); 
       }); 

       function highlightSelection() { 
        var selection; 

        //Get the selected stuff 
        if (window.getSelection) 
         selection = window.getSelection(); 
        else if (typeof document.selection != "undefined") 
         selection = document.selection; 

        //Get a the selected content, in a range object 
        var range = selection.getRangeAt(0); 

        //If the range spans some text, and inside a tag, set its css class. 
        if (range && !selection.isCollapsed) { 
         if (selection.anchorNode.parentNode == selection.focusNode.parentNode) { 
          var span = document.createElement('span'); 
          span.className = 'highlight'; 
          span.textContent = selection.toString(); 
          selection.deleteFromDocument(); 
          range.insertNode(span); 
    //      range.surroundContents(span); 
         } 
        } 
       } 

      </script> 
    </html> 

https://jsfiddle.net/Bilalchk123/1o4j0w2v/