【问题标题】:Caret position in pixels in an input type text (not a textarea) [duplicate]输入类型文本(不是文本区域)中的插入符号位置(以像素为单位)[重复]
【发布时间】:2012-11-01 02:21:50
【问题描述】:

更新Get cursor or text position in pixels for input element 的副本。

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


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

<input type='text' /> 

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

注意:我不想知道字符或&lt;textarea&gt; 中的位置。我想知道&lt;input&gt; 元素中的像素位置。

【问题讨论】:

标签: javascript html textinput caret


【解决方案1】:

使用不可见的人造元素

您可以使用绝对定位的不可见(使用visibility 而不是display)人造元素来完成此操作,该元素具有与输入文本框(字体、左边框和左填充)相同的所有 CSS 属性。

very short and easy to understand JSFiddle 是该脚本应该如何工作的起点。
它可以在 Chrome 和 Firefox 中按原样工作。it seems 它应该也可以在 IE9+ 中工作。

Internet Explorer 8(及以下版本)将 need some additional code 从输入文本框中的文本开头获取插入符号位置。我什至在顶部添加了一个仪表,以每 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"));
});​

注意假的正确尺寸

  • 填充
  • 边框
  • 边距

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

然后很容易从输入框开始以像素为单位获得插入符号的位置:

faux.outerWidth();

问题

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

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

希望这会有所帮助。

【讨论】:

  • 我认为您的回答非常棒。我很快就会把它标记为正确的(只是给其他人一个回答的机会)。我暂时不标记它的唯一原因是因为它似乎很难做到,我希望有一个更简单的解决方案。
  • @Zo72:是的,没问题。赏金还有 6 天到期,与此同时,有人可以提出一些替代解决方案,尽管我怀疑是否存在。我的解决方案并不像看起来那么难。您还可以从代码中看到它非常简单......让我们看看其他人。我自己也想看看替代品。 :)
  • @Zo72:不是。 渲染闪烁的插入符号不是浏览器的责任。那是操作系统 GUI 功能。浏览器只显示系统文本框。然后由操作系统及其 GUI 配置和功能完成闪烁。尽管我认为插入符号取决于操作系统功能,但输入框仍可能由浏览器呈现。
  • 加一个有趣的解决方案。
  • @RobertKoritnik 提到的问题可以通过用element.scrollLeft 调整插入符号的位置来解决。我已经更新了令人难以置信的轻量级和健壮的textarea-caret-position Component 库以支持&lt;input ype="text"&gt;。 jsfiddle.net/dandv/aFPA7 上的演示
【解决方案2】:

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

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

当然我们不知道按要求以 [px] 为单位的距离,但我们能够定位内容(a carret在这种情况下)完全符合比例字体的宽度,所以如果这是最终目标(如 OP 第 3 行中提到的),那么 .... voi啦啦!

<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 元素突出显示分隔符文本。留下使垫片无法选择的任务 - 有一个很好的解决方案 here

【讨论】:

  • 非常聪明的解决方案。然而,你只是在游戏中出现得太晚了。谢谢
  • 迟到总比没有好......只要它有效......我试图专注于你想要实现的目标(定位)而不是你认为你需要实现它的目标(一个 px测量 - QED 不一定相同),因此得出了一个令人惊讶的轻松答案(恕我直言)......
  • 这基本上是我提供的相同解决方案,但功能较少。我故意让假的div 可见,所以人们可以看到发生了什么。我确实说过它必须被隐藏,我也可以将它放在input 的下方。当用户在input 中输入空格时,您的解决方案也不起作用,当他们在输入中使用箭头键重新定位插入符号时,它也不起作用。总而言之:这只是我的解决方案的一小部分。除了我使用 jQuery 而你直接使用 Javascript + DOM 操作。
  • 顺便说一句:使用 visibility 隐藏您的 span 会是一个更好的选择,因为 1. 您可以避免背景冲突(想想图像)以及 2. 防止选择的附加脚本。无法选择不可见的元素。当你可以避免它们时,为什么要把事情复杂化。 简单规则.
  • 我已经更新了令人难以置信的轻量级和健壮的textarea-caret-position Component 库以支持&lt;input ype="text"&gt;。 jsfiddle.net/dandv/aFPA7 上的演示
【解决方案3】:

您可以使用&lt;span contenteditable="true"&gt;&lt;/span&gt;&lt;input type="hidden" /&gt;。这样你就可以使用window.getSelection()getRangeAtgetClientRects 来获得这个位置。这应该适用于大多数现代浏览器,包括 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。

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

【讨论】:

    【解决方案4】:

    【讨论】:

    • 我已经更新了令人难以置信的轻量级和健壮的textarea-caret-position Component 库以支持&lt;input ype="text"&gt;。 jsfiddle.net/dandv/aFPA7 上的演示。现在所有答案都已过时。
    【解决方案5】:

    canvas 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。但何知道你应该彻底检查一下! :)

    【讨论】:

    • 创意解决方案,但有点矫枉过正
    • 喂?我们正在讨论在文本框中计算像素的解决方案。谁需要那个?尽管如此,我认为它比这里的任何其他解决方案都要准确得多,而且代码并不复杂。但这只是我的意见。
    • 一个以像素为单位获取插入符号位置的明显准确的解决方案,它不实例化canvas 对象,由令人难以置信的轻量级和健壮的textarea-caret-position 组件 实现图书馆。我刚刚更新了它以支持&lt;input type="text"&gt;。 jsfiddle.net/dandv/aFPA7 上的演示
    【解决方案6】:

    这是一个工作示例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

    【讨论】:

    • 不适用于比例字体....输入字段字符串“my bllllllllllllllllllll”,每次输入字母“l”(lima)后,差距会越来越大
    • 一封信的大小是多少?考虑像 i、m、w 这样的字母具有巨大的宽度差异。这仅适用于等距字体。
    • @MikeD: 或输入 wwwwwwwwwmmmmmmmm
    • 确实有一些环境可以知道 [px] 中比例字母的实际宽度(字体类别)。也许输入的字符串可以复制 on_Change() 并以与背景略有不同的颜色再次显示在下方,以用作不断增长的占位符...(推测)
    • 我已经更新了令人难以置信的轻量级和健壮的textarea-caret-position Component 库以支持&lt;input type="text"&gt;。 jsfiddle.net/dandv/aFPA7 上的演示。它支持任何你想扔给它的东西,wwwwiiii
    【解决方案7】:
    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'))
    

    【讨论】:

    • Ivlev 没有告诉我以像素为单位的位置。
    • 你最初的帖子是关于光标位置的
    • 我认为你现在应该删除你的答案。如果您不知道已更改问题的答案。如果您不喜欢更改,您可以做的最多是对问题投反对票。最好也编辑答案:)
    • @KirillIvlev 不,我原来的问题是以像素为单位的
    猜你喜欢
    • 2013-04-19
    • 1970-01-01
    • 2011-05-26
    • 1970-01-01
    • 1970-01-01
    • 2012-02-19
    • 2022-01-14
    • 1970-01-01
    相关资源
    最近更新 更多