【问题标题】:Firefox triple click selection returns incorrect start and end offsetsFirefox 三击选择返回不正确的开始和结束偏移量
【发布时间】:2014-01-21 12:01:35
【问题描述】:

我有这段代码应该返回用户选择的开始和结束偏移:

<!DOCTYPE html>
 <html>
  <head>
   <script type="text/javascript">
    function getSelRange() {
      var selObj = window.getSelection();
      var range  = selObj.getRangeAt(0);
      alert(range.startOffset+"-"+range.endOffset);
    }

   </script>
  </head>
  <body>
    <button onclick="getSelRange()">Get the selected text!</button>
    <p>Select some text!</p>
  </body>
</html>

当我通过拖动从p 中选择一些文本时,它会正确提醒数字。但是,当我通过三次单击选择p 中的整个文本时,它会发出警告0-1。看起来仅在 Firefox 中,三次单击无法正确返回选择范围。

如何在三次点击时也获得正确的起点和终点?

【问题讨论】:

    标签: javascript html firefox selection


    【解决方案1】:

    Firefox 正在返回正确的范围。问题是您假设范围必须具有相对于文本节点的开始和结束边界是不正确的。

    发生的情况是 Firefox 将范围报告为在 &lt;p&gt; 元素的第零个子节点之前开始并在 &lt;p&gt; 元素的第一个子节点之后结束。这是完全有效的。

    您可以执行以下操作来调整此类范围,使其边界位于 &lt;p&gt; 元素内的文本节点内:

    演示:http://jsfiddle.net/DbmjH/2/

    代码:

    function adjustRange(range) {
        range = range.cloneRange();
        if (range.startContainer.nodeType != 3) {
            var nodeAfterStart = range.startContainer.childNodes[range.startOffset];
            if (nodeAfterStart && nodeAfterStart.nodeType == 3) {
                range.setStart(nodeAfterStart, 0);
            }
        }
        if (range.endContainer.nodeType != 3 && range.endOffset >= 1) {
            var nodeBeforeEnd = range.endContainer.childNodes[range.endOffset - 1];
            if (nodeBeforeEnd && nodeBeforeEnd.nodeType == 3) {
                range.setEnd(nodeBeforeEnd, nodeBeforeEnd.data.length);
            }
        }
        return range;
    }
    

    【讨论】:

    • 蒂姆这是我在回答中得到的相同输出
    • @Zword:可能是这样,举个例子。一般来说,它们根本不一样。我真的不明白你的答案是想做什么。
    • 哈哈,当问题涉及选择范围时,我总是可以期待 Tim 的回答。 :)
    • @Cupidvogel:不像几年前那么可靠
    • @Marc:不是这样的错误。 Rangy 抽象了 API 差异(主要是 IE
    【解决方案2】:

    Check this fiddle (更新)

    我已经做到了,当段落包含多行时,它可以在三次单击时工作。

    <script>
        function getSelRange() {
            var selObj = window.getSelection();
            var range = selObj.getRangeAt(0);
            var r = document.getElementById('txt').innerHTML.split('<br>');
    
            if (r[(range.endOffset-1)/2] == selObj) {
                alert(0+"-"+r[(range.endOffset-1)/2].length);
            } else if (range.startOffset >= range.endOffset) {
                alert(range.startOffset + "-" + r[(range.endOffset-1)/2].length);
            } else {
                alert(range.startOffset + "-" + range.endOffset);
            }  
        }
    </script>
    

    New Added Fiddle

    <script>
    function getSelRange() {
        var selObj = window.getSelection();
        var range  = selObj.getRangeAt(0);
        var r=document.getElementById('txt').innerHTML.split('<br>');
        var selLines = selObj.toString().split('\n');
    
        var Str = document.getElementById('txt').innerHTML;
        Str=Str.replace(/<br>/g,"xzznlzzx");
        var pr=selObj.toString().replace(/\r?\n/g,"xzznlzzx");
        var rStr=Str.substring(0,Str.indexOf(pr));
    
        var rSplit=rStr.split('xzznlzzx');
        var prSplit=pr.split('xzznlzzx');
    
        var countStart=0;
        var countEnd=0;
        var i=0;
        for(;i<(rSplit.length-1);i++)
        {
            countStart=countStart+r[i].length;
        }
        for(j=0;j<(prSplit.length-1);i++,j++)
        {
            countEnd=countEnd+r[i].length;
        }
    
        countEnd=countEnd+countStart;
        if(r[(range.endOffset-1)/2]==selObj)
        {
        alert((0+countStart)+"-"+(r[(range.endOffset-1)/2].length+countEnd));
        }
        else{
            if(r[i].length<selObj.toString().length)
            {
            var indx = selObj.toString().indexOf(r[i]);
            }
            else{
            var indx = r[i].indexOf(selObj.toString());
            var vals=selObj.toString().length;
            var res = r[i].substring(indx+vals,indx+vals+1);
            if(res==""){indx=1}
            else{indx=-1}
            }
            if(indx!=-1)
            {
            alert((range.startOffset+countStart)+"-"+(r[i].length+countEnd));
            }
            else{
            alert((range.startOffset+countStart)+"-"+(range.endOffset+countEnd));
            }
        } 
    }
    </script>
    

    注意:为了使上述小提琴能够工作,&lt;p&gt; 标记中的字符串必须在一行中,否则它将在单词之间添加额外的空格。

    【讨论】:

    • 它几乎可以工作,但如果我将p 的内部HTML 更改为Check this out&lt;br&gt;Foo 使其成为两行,那么如果我通过三次单击选择任一行,它仍然返回0-1 ..
    • 谢谢。但是现在另一个问题,如果选择是通过拖动和跨越多行进行的,比如从第二行的中间到第三行的中间,那么开始和结束都相对于相应的行单独计算。跨度>
    • 你能告诉我选择多行时你想要什么输出吗?
    • 我希望开始和结束好像p中的整个文本是一口气,没有&lt;br&gt;
    • @Cupidvogel 我添加了一个新的小提琴。代码有点长,因为它需要许多检查才能使其工作。希望这对你有所帮助
    猜你喜欢
    • 2020-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 2014-08-03
    相关资源
    最近更新 更多