获取文本输入框内光标位置(以字符为单位)

300
如何获得输入框内的插入符位置?
我通过谷歌找到了一些资料,但都不是很可靠。理想情况下,可以使用类似于jQuery插件的东西来实现,这样就可以轻松地执行:
$("#myinput").caretPosition()

3
尝试搜索"光标位置",这样可以得到更多的搜索结果,以及一些关于此问题的SO主题。 - Alec
2
可能是与此问题重复:如何获得文本框中的光标位置?。另请参阅:FieldSelection插件 - Christian C. Salvadó
2
@CMS 在<input>中查找位置比在<textarea>中查找位置要简单得多。 - Andrew Mao
1
@AndrewMao:如果文本已滚动且插入符号在“size”字符之后,那么会更加困难。 - Dan Dascalescu
@alec:我同意搜索光标而不是插入符可能会得到更多的结果。正如其他地方指出的那样,我了解到“插入符”是更合适的术语。“光标”代表任何位置,而“插入符”则特指文本中的位置。 - Suncat2000
10个回答

308

更简单的更新方式:

使用field.selectionStart这个答案中的示例

感谢@commonSenseCode指出了这一点。


旧答案:

找到了这个解决方案。虽然不是基于jQuery,但将其集成到jQuery中没有问题:

/*
** Returns the caret (cursor) position of the specified text field (oField).
** Return value range is 0-oField.value.length.
*/
function doGetCaretPosition (oField) {

  // Initialize
  var iCaretPos = 0;

  // IE Support
  if (document.selection) {

    // Set focus on the element
    oField.focus();

    // To get cursor position, get empty selection range
    var oSel = document.selection.createRange();

    // Move selection start to 0 position
    oSel.moveStart('character', -oField.value.length);

    // The caret position is selection length
    iCaretPos = oSel.text.length;
  }

  // Firefox support
  else if (oField.selectionStart || oField.selectionStart == '0')
    iCaretPos = oField.selectionDirection=='backward' ? oField.selectionStart : oField.selectionEnd;

  // Return results
  return iCaretPos;
}

9
else if (oField.selectionStart || oField.selectionStart == '0') could be else if (typeof oField.selectionStart==='number') - user2428118
“oField.focus()” 的作用是什么?没有这行代码也可以运行。如果您在输入框上使用 blur 事件并在回调函数中执行该函数,请小心。 - Kirill Reznikov
你是在IE上测试吗?整个if部分只在IE上执行。在IE中,只有全局选择,所以它是document.selection而不是field.selection或其他什么。此外,在IE 7中可以选择某些内容,然后通过TAB键离开字段而不会失去选择。这样,当文本被选中但字段没有焦点时,document.selection返回零选择。这就是为什么,在读取document.selection之前,需要将焦点放在元素上以解决此错误的解决方法。 - bezmax
始终在Chrome和Firefox中获得0 - Kaushik Thanki

231
使用selectionStart。它与所有主要浏览器兼容

document.getElementById('foobar').addEventListener('keyup', e => {
  console.log('Caret at: ', e.target.selectionStart)
})
<input id="foobar" />

仅在未定义类型或输入上的type="text"type="textarea"时才有效。


4
如果我使用鼠标改变位置,控制台不会打印出来。有没有办法解决这个问题? - Eugene Barsky
6
@EugeneBarsky 只需为单击事件添加新的事件侦听器。您可以随时检查.selectionStart属性(document.getElementById('foobar').selectionStart),它不必在事件侦听器内部。 - JJJ
6
很棒,但当输入类型为数字时,在Firefox或Chrome中无法使用。 - Adam R. Grey
1
@JJJ 属性 'selectionStart' 在类型 'HTMLElement' 上不存在。 - MojioMS
@MojioMS 这个确实存在于 HTMLInputElement 的一部分中,正如已经指出的那样,如果目标是文本类型或文本区域类型,则会起作用。 - Sam Stephenson
3
和本页面上的其他答案一样,如果您开始突出显示一个选择并将光标移动到选择的末尾,这将给出错误的值。选择开头和选择结尾不同于光标位置。光标可以在其中一端。 - ggorlen

119

如果有人想使用,我已经将bezmax的答案中的功能封装到jQuery中。

(function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if ('selectionStart' in input) {
            // Standard-compliant browsers
            return input.selectionStart;
        } else if (document.selection) {
            // IE
            input.focus();
            var sel = document.selection.createRange();
            var selLen = document.selection.createRange().text.length;
            sel.moveStart('character', -input.value.length);
            return sel.text.length - selLen;
        }
    }
})(jQuery);

3
input = $(this).get(0)input = this 不是同一回事吗? - Mic
5
不,在jQuery插件中不需要这样做。在插件中,this 指的是一个完整的包装集合。但他的代码仍然有误,正确的方式是 this.get(0)。尽管如此,他的代码可能仍然有效,因为重新包装一个已经被包装的集合不会产生任何效果。 - Chev
1
这给了我错误的信息。我在查看输入文本时关注光标位置。我演示这个问题的代码片段是:http://jsfiddle.net/fallenreaper/TSwyk/ - Fallenreaper
1
当输入为数字类型时,Firefox在input.selectionStart上生成NS_ERROR_FAILURE,是否将其包装在try {} catch {}中? - niall.campbell
如果您添加该函数的用法,对于新手来说会很好。 - Muhammad Omer Aslam

27

有一个非常简单的解决方案。使用以下代码并得到验证结果-

<html>
<head>
<script>
    function f1(el) {
    var val = el.value;
    alert(val.slice(0, el.selectionStart).length);
}
</script>
</head>
<body>
<input type=text id=t1 value=abcd>
    <button onclick="f1(document.getElementById('t1'))">check position</button>
</body>
</html>

我给你提供了fiddle_demo


19
“切片”是一个相对昂贵的操作,它对这个“解决方案”没有任何帮助——el.selectionStart等同于你的切片长度,请直接返回该值。此外,其他解决方案更加复杂的原因是它们处理不支持selectionStart的其他浏览器。 - mpen
3
我曾经辞掉过一些工作,原因是我不得不使用像这样的变量名称编写代码。 - Michael Scheper
2
@Michael Scheper - 你是指“el”代表元素,“val”代表值吗?这些都很常见... - user2782001
14
我口误了,我的主要关注点在于函数名称。f1 跟 'user2782001' 差不多没有意义。 - Michael Scheper

17
现在有一个很好的插件: Caret插件 然后你可以使用$("#myTextBox").caret()获取位置,或者通过$("#myTextBox").caret(position)设置位置。

1
插件caret似乎是针对文本区域元素而不是输入框的。 - schmidlop
4
我已经让<input type="text" id="myTextBox"/>正常工作,并使用上述代码。 - Jens Mikkelsen
我刚刚在input:text和textarea中成功地使用了这个不错的插件,至少在FF中它表现得非常好,感谢您的建议! - AFract

14
这里有几个好的答案,但我认为你可以简化代码并跳过对inputElement.selectionStart支持的检查:它仅在IE8及更早版本上不支持(参见文档),这仅占当前浏览器使用率的不到1%。
var input = document.getElementById('myinput'); // or $('#myinput')[0]
var caretPos = input.selectionStart;

// and if you want to know if there is a selection or not inside your input:

if (input.selectionStart != input.selectionEnd)
{
    var selectionValue =
    input.value.substring(input.selectionStart, input.selectionEnd);
}

14
   (function($) {
    $.fn.getCursorPosition = function() {
        var input = this.get(0);
        if (!input) return; // No (input) element found
        if (document.selection) {
            // IE
           input.focus();
        }
        return 'selectionStart' in input ? input.selectionStart:'' || Math.abs(document.selection.createRange().moveStart('character', -input.value.length));
     }
   })(jQuery);

3
也许您需要选择范围而不仅仅是光标位置。这里有一个简单的函数,您甚至不需要jQuery:
function caretPosition(input) {
    var start = input[0].selectionStart,
        end = input[0].selectionEnd,
        diff = end - start;

    if (start >= 0 && start == end) {
        // do cursor position actions, example:
        console.log('Cursor Position: ' + start);
    } else if (start >= 0) {
        // do ranged select actions, example:
        console.log('Cursor Position: ' + start + ' to ' + end + ' (' + diff + ' selected chars)');
    }
}

假设您想在输入框发生更改或鼠标移动光标位置时调用它(在本例中,我们使用jQuery的.on())。出于性能原因,如果事件不断涌入,可以考虑添加setTimeout()或类似Underscores的_debounce()

$('input[type="text"]').on('keyup mouseup mouseleave', function() {
    caretPosition($(this));
});

如果您想试试,这里有一个Fiddle:https://jsfiddle.net/Dhaupin/91189tq7/


0

解决方案是.selectionStart

var input = document.getElementById('yourINPUTid');
input.selectionEnd = input.selectionStart = yourDESIREDposition;
input.focus();

如果未分配.selectionEnd,则会选择一些文本(S->E)。
当焦点丢失时,需要使用.focus();当您触发代码(onClick)时。
我只在Chrome中测试过这个。
如果您想要更复杂的解决方案,您必须阅读其他答案。

这个问题询问如何获取位置,而不是设置 - EvgenKo423

0

const inpT = document.getElementById("text-box");
const inpC = document.getElementById("text-box-content");
// swch gets  inputs .
var swch;
// swch  if corsur is active in inputs defaulte is false .
var isSelect = false;

var crnselect;
// on focus
function setSwitch(e) {
  swch = e;
  isSelect = true;
  console.log("set Switch: " + isSelect);
}
// on click ev
function setEmoji() {
  if (isSelect) {
    console.log("emoji added :)");
    swch.value += ":)";
    swch.setSelectionRange(2,2 );
    isSelect = true;
  }

}
// on not selected on input . 
function onout() {
  // الافنت  اون كي اب 
  crnselect = inpC.selectionStart;
  
  // return input select not active after 200 ms .
  var len = swch.value.length;
  setTimeout(() => {
   (len == swch.value.length)? isSelect = false:isSelect = true;
  }, 200);
}
<h1> Try it !</h1>
    
  <input type="text" onfocus = "setSwitch(this)" onfocusout = "onout()" id="text-box" size="20" value="title">
  <input type="text" onfocus = "setSwitch(this)"  onfocusout = "onout()"  id="text-box-content" size="20" value="content">
<button onclick="setEmoji()">emogi :) </button>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接