26

更新:获取输入元素的光标或文本位置(以像素为单位)的副本。

TL; DR - 使用令人难以置信的轻量级和健壮的 textarea-caret-position 组件库,现在也支持<input ype="text">。演示在http://jsfiddle.net/dandv/aFPA7/


有没有办法知道插入符号在 HTML 文本字段中的位置?

<input type='text' /> 

我想根据插入符号的位置以像素为单位(并重新定位)div。

注意:我不想知道字符或<textarea>. 我想知道<input>元素中像素的位置。

4

7 回答 7

18

使用不可见的人造元素

您可以通过使用绝对定位的不可见(使用visibilitynot display)虚假元素来实现这一点,该元素具有与输入文本框(字体、左边框和左填充)相同的所有 CSS 属性。

这个非常简短且易于理解的 JSFiddle是该脚本应该如何工作的起点。
它可以在 Chrome 和 Firefox 中按原样运行。它似乎也应该在 IE9+ 中工作。

Internet Explorer 8(及以下)需要一些额外的代码才能从输入文本框中的文本开头获取插入符号的位置。我什至在顶部添加了一个仪表,以每 10 个像素显示一条线,以便您查看它是否正确测量。请注意,线条位于 1、11、21、... 像素位置。

这个例子实际上是把文本框中的所有文本放到插入符号的位置,然后把它放在人造元素内,然后测量它的宽度(以像素为单位)。这使您从文本框的左侧偏移。

当它将文本复制到人造元素时,它还会用不间断的空格替换普通空格,因此它们实际上会被渲染,否则如果您将插入符号放置在空格之后,您会得到错误的位置:

var faux = $("#faux");
$("#test").on("keyup click focus", function(evt) {
    // get caret offset from start
    var off = this.selectionStart;

    // replace spaces with non-breaking space
    faux.text(this.value.substring(0, off).replace(/\s/g, "\u00a0"));
});​

注意人造的正确尺寸

  • 填充
  • 边界
  • 利润

已被删除以获得正确的值,否则元素会太宽。元素的框必须在它包含的文本之后结束。

Caret 从输入框开始的像素位置可以很容易地从以下位置获得:

faux.outerWidth();

问题

不过有一个问题。我不确定如何处理文本框中的文本滚动(太长时)并且插入符号不在文本的最后但介于两者之间的情况...如果它在末尾,则插入符号位置始终在可能的最大位置(输入宽度减去右侧尺寸 - 填充、边框、边距)。

我不确定是否可以在文本框中获取文本滚动位置?如果可以,那么即使这个问题也可以解决。但我不知道有任何解决方案...

希望这可以帮助。

于 2012-11-15T16:33:33.753 回答
4

详细说明我上面的评论,我想以下应该可行。

为了说明我省略了格式的原理,因此可能需要将元素 (id="spacer") 颜色设置为#FFFFFE,可能需要添加一些前导空格的像素等......但是现在 carret 将按比例移动 - 前提是 id 的测试和间隔使用相同的字体。

当然,我们不知道[px]中的距离,但我们能够完全按照比例字体的宽度定位内容(在这种情况下为 carret),所以如果这是最终目标(如前所述在OP 第 3 行),然后....瞧!

<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    </head>
    <body>
        <script type="text/javascript">
            function adjust()
            {
                document.getElementById('spacer').innerHTML=document.getElementById('test').value;
            }
        </script>
        <p>
            <input name="test" id="test" type="text" onkeyup="adjust()" /> Test <br />
            <span id="spacer"></span>^here
        </p>
    </body>
</html>

更新:

<span id="spacer" style="color: #FFFFFF"></span>

这将使分隔符在白色背景上不可见,但不会阻止用户通过选择 span 元素突出显示分隔符文本。留下使垫片无法选择的任务 - 这里有一个很好的解决方案

于 2012-11-20T08:39:48.287 回答
2

你可以使用<span contenteditable="true"></span><input type="hidden" />. 这样您就可以使用window.getSelection()withgetRangeAtgetClientRects来获得该职位。这应该适用于大多数现代浏览器,包括 IE9+:

function getCaret() {
    var caret = caret = {top: 0, height: 0},
        sel = window.getSelection();
    caret.top = 0;
    caret.height = 0;
    if(sel.rangeCount) {
        var range = sel.getRangeAt(0);          
        var rects = range.getClientRects();
        if (rects.length > 0) {
            caret.top = rects[0].top;
            caret.height = rects[0].height;
        } else {
            caret.top = range.startContainer.offsetTop - document.body.scrollTop;
            caret.height = range.startContainer.clientHeight;
        }
    }
    return caret;
}

(请记住,我从中提取的项目是针对 Mobile Safari,并使用一个大的 contenteditable 视图。您可能需要对其进行调整以满足您的需求。更多的是用于演示如何获取 X 和 Y 坐标。)

对于 IE8 及以下版本,IE 具有用于获取相同信息的专有 API。

棘手的部分是确保您的元素只允许纯文本。特别是粘贴事件。当跨度失去焦点(onblur)时,您希望将内容复制到隐藏字段中以便发布。

于 2012-11-19T19:58:45.140 回答
1

2D画布呢?它有用于绘制测量文本的 API。你可以用那个。设置相同的字体,字体大小,您应该能够从文本框中测量字符串的宽度。

      $('body').append('<canvas id="textCanvas" width="100px" height="100px">I\'m sorry your browser does not support the HTML5 canvas element.</canvas>');
      var canvas = document.getElementById('textCanvas');
      var ctx = canvas.getContext('2d');
      ctx.measureText(text);
      var width = mes.width;

我使用这种解决方案来获取一些文本的宽度以在 WebGL 中绘制它。我工作得很好,但我从来没有测试过当文本对于画布上下文来说太大时会发生什么,我认为这会很好,因为它是用于测量文本的 API。但何知道你应该彻底检查一下!:)

于 2012-11-19T18:35:38.023 回答
0

这是一个工作示例http://jsfiddle.net/gPL3f/2/

为了找到插入符号的位置,我计算了输入中的字母并将该值乘以 1 个字母的大小。

然后将 div 移动到该位置。

<html>
<head>
<style type="text/css">
body { font-size: 12px; line-height: 12px; font-family: arial;}
#box { width: 100px; height: 15px; position: absolute; top: 35px; left: 0px; background: pink;}
</style>
<script type="text/javascript" src="jquery-1.7.1.js"></script>
<script type="text/javascript">
$(document).ready(function(){
var letter_size = 6;
$("input[type='text']").keyup(function(e) {
    move_size = $(this).val().length * letter_size;
    $('#box').css({'left': move_size+'px'}); 
});
});
</script>

</head>
<body>
<input type="text" />
<div id="box">
/ move 
</div>
</body>
<html>

更新

$(document).ready(function(){
    var letter_size = 6;
    $("input[type='text']").keyup(function(e) {
        $('.hidden_for_width').text($(this).val());
        move_size = $('.hidden_for_width').width();
        $('#box').css({'left': move_size});
    });
});

添加了一个隐藏容器,我在其中插入来自 input 的值。之后我得到该容器的宽度并相应地移动我的 DIV

于 2012-11-18T23:54:56.100 回答
-1
function getCursorPosition (elem) {
  var pos = 0;  
  if (document.selection) {
    elem.focus ();
    var sele = document.selection.createRange();
    sele.moveStart('character', -elem.value.length);
    pos = sele.text.length;
  }
  else if (elem.selectionStart || elem.selectionStart == '0')
    pos = elem.selectionStart;
  return pos;
}​

getCursorPosition(document.getElementById('textbox1'))
于 2012-11-12T16:32:40.287 回答