如何获取文本区域中所选文本的屏幕坐标

Ste*_*hRT 6 javascript dom textarea

嘿,我正在尽力弄清楚如何获取文本区域字段中突出显示的单词的 X/Y

这是我当前的代码:

<!DOCTYPE html>
<html>
<head>
<script type="text/javascript" src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script>
<script type="text/javascript">
var X = 0;
var Y = 0;

function selectHTML() {
    try {
        if (window.ActiveXObject) {
            var c = document.selection.createRange();
            return c.htmlText;
        }

        X = getSelection().getRangeAt(0).endOffset;
        Y = getSelection().getRangeAt(0).startOffset;
        w.surroundContents(nNd);

        return nNd.innerHTML;
    } catch (e) {
        if (window.ActiveXObject) {
            return document.selection.createRange();
        } else {
            return getSelection();
        }
    }
}

function FindTextInsideField() {
    var str = document.getElementById("FindText").value;
    var supported = false;
    var found = false;

    if (window.find) {
        supported = true;
        found = window.find(str);

        let pos = document.getElementById("FindText").value.indexOf(str);

        if (pos >= 0) {
            document.getElementById("FindText").setRangeText(str, pos, pos + 4, "select");
            document.getElementById("FindText").focus();
        }

        $('#FindText').val("");
    } else {
        if (document.selection && document.selection.createRange) {
            var textRange = document.selection.createRange();

            if (textRange.findText) {
                supported = true;

                if (textRange.text.length > 0) {
                    textRange.collapse(true);
                    textRange.move("character", 1);
                }

                found = textRange.findText(str);

                if (found) {
                    textRange.select();
                }
            }
        }

        $('#FindText').val("");
    }

    if (supported) {
        if (!found) {
            alert("The following text was not found:\n" + str);
            $('#FindText').val("");
        }
    } else {
        alert("Your browser does not support this example!");
        $('#FindText').val("");
    }
}

function findXY() {
    var mytext = selectHTML();
    $('#_findXY').val("X = " + X + "  Y = " + Y);
}
</script>
</head>
<body>
 <textarea id = "paragraph_text" name = "paragraph_text" cols = "100" rows = "30" > Lorem ipsum dolor sit amet, eam iusto regione at.Mei id clita legendos.His ipsum neglegentur id, elit oblique no eos.Eum at clita eruditi.Vix quem hinc ex, meliore deserunt vix id, ei error ludus impetus ius.At evertitur elaboraret mel, sonet dolorum repudiandae mea at.
An iusto menandri repudiare mel, eu iisque definiebas pri, semper convenire eam ne.In ius percipit consequat.Ut sumo offendit quo.In duo epicuri nostrum eligendi, essent regione sed no.
In exerci doming splendide sit, mel omnes delicatissimi ei, at virtute vulputate efficiantur his.Quo possim civibus eu, hinc soluta ius ex.Ea quem dolor veniam mel.Sea ex paulo labores laboramus, te illud ludus mel.
Quo vidit nostrum postulant no, paulo doctus diceret vim et, sumo nullam reprehendunt in mei.Eu vis amet commune delicatissimi.Falli impedit in sea.Soluta appareat phaedrum ea sea.Sea facete postulant necessitatibus at, sea veri probo no.

---------------------------------------------------------------------------------------------- -

 </textarea >
 <br/>
 <input type = "text" id = "FindText" value = "percipit" size = "20" / >
 <button onclick = "FindTextInsideField();" > Find! </button>
 <input type = "text" style = "margin-left: 30px;" id = "_findXY" value = "" size = "20" readonly />
 <button onclick = "findXY();" > Get X / Y cords </button>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

突出显示这个词效果很好。您可以将要搜索的任何单词放入文本区域内。但是,一旦您按下“获取 X/Y”线,它会显示X = 5 Y = 5 ,这是不正确的,因为根据codePen代码示例,它应该位于X = ~250px by Y = ~80px区域。

有人知道如何解决这个问题或者甚至可以解决吗?

在此输入图像描述

Pau*_*ler 6

第一个问题:startOffsetendOffset屏幕上选择的位置无关。相反,它们与选择开始startContainer和结束处的字符或节点位置相关。endContainer这允许您确定跨越多个元素的选择的开始和结束字符或节点索引(想象一个选择从段落的粗体区域开始并在其外部结束,startOffset将是粗体元素文本内的索引,并且将是粗体元素之后的范围endOffset内的索引)。Text

Range好消息:调用的对象上有一个实验函数getBoundingClientRect,它确实可以获取当前选择周围的边界框的屏幕坐标。

问题:不幸的是,至少在 Google Chrome 中,当选择位于 a或getBoundingClientRect内时,不会返回准确的坐标。因此,除非您可以避免使用,例如通过使用内容可编辑 div (请参阅: https: //developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content),此解决方案可能不适合您。textareainputtextarea

疯狂的替代方案:该Canvas对象具有测量文本尺寸的功能,因此,如果您真的很顽固,理论上您可以测量 中包含的文本的尺寸textarea,包括模拟自动换行行为,以便独立计算所选文本的位置在 之内textarea(不要忘记考虑滚动偏移)。


Range这是一个片段,直观地演示了选择对象发生变化时的状态。

var outline = document.getElementById('selection_outline');
var start_container = document.getElementById('start_container');
var end_container = document.getElementById('end_container');
var start_offset = document.getElementById('start_offset');
var end_offset = document.getElementById('end_offset');

document.addEventListener('selectionchange', function() {
  var selection = document.getSelection();
  if (selection) {
    var range = selection.getRangeAt(0);
    if (range) {
      var bounds = range.getBoundingClientRect();
      outline.style.top = `${bounds.top + window.scrollY}px`;
      outline.style.left = `${bounds.left + window.scrollX}px`;
      outline.style.width = `${bounds.width}px`;
      outline.style.height = `${bounds.height}px`;
      
      start_container.value = range.startContainer.tagName || range.startContainer.parentNode.tagName;
      end_container.value = range.endContainer.tagName || range.endContainer.parentNode.tagName;
      
      start_offset.value = range.startOffset;
      end_offset.value = range.endOffset;
    }
  }
})
Run Code Online (Sandbox Code Playgroud)
#selection_outline {
  position: absolute;
  border: 2px solid red;
  pointer-events: none;
}

.flow-wrap-row {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
}

.flow-wrap-row > * {
  white-space: nowrap
}

.flow-wrap-row > li {
  margin-right: 1.5em;
}

ul {
 padding-left: 1.5em;
}

input {
 width: 80px;
}
Run Code Online (Sandbox Code Playgroud)
<p>This is <b>a complex element</b> with lots of selectable text <i>and nested, <b> and double nested</b> elements</i>!!!</p>
<textarea cols="60" rows="5">Here is a text area with some simple content.</textarea>
<div contenteditable="true">Here is a contenteditable div with some simple content.</div>
<ul class="flow-wrap-row">
  <li><label>startContainer: <input id="start_container" type="text" /></label></li>
  <li><label>endContainer: <input id="end_container" type="text" /></label></li>
  <li><label>startOffset: <input id="start_offset" type="text" /></label></li>
  <li><label>endOffset: <input id="end_offset" type="text" /></label></li>
</ul>
<div id="selection_outline"></div>
Run Code Online (Sandbox Code Playgroud)