【问题标题】:How to get the screen coordinates for the selected text within a textarea如何获取文本区域内选定文本的屏幕坐标
【发布时间】:2019-12-05 19:25:21
【问题描述】:

大家好,我正在尽力弄清楚如何在 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>

突出显示这个词就可以了。您将要搜索的任何单词放在文本区域内。但是,一旦您按下 Get X/Y 线,它就会显示 X = 5 Y = 5,这是不正确的,因为它应该在 X = ~250px 中Y = ~80px 根据codePen 代码示例的竞技场。

任何人都知道如何解决这个问题,或者它甚至可以解决吗?

【问题讨论】:

  • 如果我的回答在某些方面不足,您介意接受我的回答或发表评论吗?这是一个有趣的调查和回答。好问题。

标签: javascript dom textarea


【解决方案1】:

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

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

The rub: Unfortunately, at least in Google Chrome, getBoundingClientRect does not return accurate coordinates when a selection is within a textarea or input.因此,除非您可以避免使用 textarea,例如使用内容可编辑的 div(参见:https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Editable_content),否则此解决方案可能不适合您。

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


这是一个 sn-p,它直观地展示了选择 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;
    }
  }
})
#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;
}
<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>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 2014-05-26
    • 2013-10-27
    • 2011-03-21
    • 1970-01-01
    • 2011-09-19
    相关资源
    最近更新 更多