在HTML文本框中设置键盘插入符位置

236

有没有人知道如何将文本框中的键盘插入符移动到特定位置?

例如,如果一个文本框(例如输入元素,而不是文本区域)中有50个字符,并且我想将插入符定位在第20个字符之前,该怎么做?

这与此问题有所区别:jQuery设置文本区域中的光标位置 ,后者需要使用jQuery。

11个回答

250

本文摘自Josh Stodola的 用JavaScript设置文本框或文本区域中的光标位置

一个通用的函数,可以让您将光标插入到文本框或文本区域的任何位置:

function setCaretPosition(elemId, caretPos) {
    var elem = document.getElementById(elemId);

    if(elem != null) {
        if(elem.createTextRange) {
            var range = elem.createTextRange();
            range.move('character', caretPos);
            range.select();
        }
        else {
            if(elem.selectionStart) {
                elem.focus();
                elem.setSelectionRange(caretPos, caretPos);
            }
            else
                elem.focus();
        }
    }
}

第一个期望参数是您希望在其上插入键盘光标的元素的ID。如果找不到该元素,则不会发生任何事情(显然)。第二个参数是光标位置索引。零将在开头放置键盘光标。如果传递的数字大于元素值中字符数,则会将键盘光标放置在末尾。

在IE6及以上版本、Firefox 2、Opera 8、Netscape 9、SeaMonkey和Safari上进行了测试。不幸的是,在Safari中,它与onfocus事件的组合不起作用)。

以下是使用上述函数将键盘光标强制跳转到页面上所有文本区域末尾的示例:

function addLoadEvent(func) {
    if(typeof window.onload != 'function') {
        window.onload = func;
    }
    else {
        if(func) {
            var oldLoad = window.onload;

            window.onload = function() {
                if(oldLoad)
                        oldLoad();

                func();
            }
        }
    }
}

// The setCaretPosition function belongs right here!

function setTextAreasOnFocus() {
/***
 * This function will force the keyboard caret to be positioned
 * at the end of all textareas when they receive focus.
 */
    var textAreas = document.getElementsByTagName('textarea');

    for(var i = 0; i < textAreas.length; i++) {
        textAreas[i].onfocus = function() {
            setCaretPosition(this.id, this.value.length);
        }
    }

    textAreas = null;
}

addLoadEvent(setTextAreasOnFocus);

6
如果(elem.selectionStart)在selectionStart为0时会出错,正如jhnns的答案所指出的那样。 - mpartel
1
这对我不起作用。当我单击实际文本框时,我希望插入符号位置在开头。请查看我的fiddle http://jsfiddle.net/khx2w/ - elad.chen
setCaretPosition函数运行良好。然而,你的addActionHandler函数却不行。但即使没有它,我也无法在焦点上移动光标。很可能是因为浏览器根据点击位置自己设置光标位置。从我所知道的来看,似乎没有办法绕过它,但我可能完全错了。 - GJK
在IE9和FF25中可以运行,但在Chrome 30中无法运行。总比没有好! - Umber Ferrule
1
博客链接已失效。 - Cloud
显示剩余5条评论

54

答案中的链接已经失效,这个链接应该可以使用(所有功劳归功于blog.vishalon.net):

http://snipplr.com/view/5144/getset-cursor-in-html-textarea/

万一这段代码再次丢失,以下是两个主要函数:

function doGetCaretPosition(ctrl)
{
 var CaretPos = 0;

 if (ctrl.selectionStart || ctrl.selectionStart == 0)
 {// Standard.
  CaretPos = ctrl.selectionStart;
 }
 else if (document.selection)
 {// Legacy IE
  ctrl.focus ();
  var Sel = document.selection.createRange ();
  Sel.moveStart ('character', -ctrl.value.length);
  CaretPos = Sel.text.length;
 }

 return (CaretPos);
}


function setCaretPosition(ctrl,pos)
{
 if (ctrl.setSelectionRange)
 {
  ctrl.focus();
  ctrl.setSelectionRange(pos,pos);
 }
 else if (ctrl.createTextRange)
 {
  var range = ctrl.createTextRange();
  range.collapse(true);
  range.moveEnd('character', pos);
  range.moveStart('character', pos);
  range.select();
 }
}

1
基本函数+1,但需要进行一些调整。在使用范围方法时,必须从“pos”中减去行数。 - Rob W

41

由于我实际上非常需要这个解决方案,而典型的基准解决方案(将输入框聚焦-然后将值设置为自身在跨浏览器中不起作用,因此我花了一些时间调整和编辑所有内容以使其正常工作。在 @kd7 的代码基础上,这就是我想出来的。

享受吧!适用于IE6+、Firefox、Chrome、Safari、Opera

跨浏览器插入符号定位技术(示例:将光标移动到结尾处)

// ** USEAGE ** (returns a boolean true/false if it worked or not)
// Parameters ( Id_of_element, caretPosition_you_want)

setCaretPosition('IDHERE', 10); // example

主要内容是@kd7的setCaretPosition函数,其中最大的调整是if (el.selectionStart || el.selectionStart === 0)。在Firefox中,selectionStart从0开始,在布尔逻辑中显然转换为False,所以它会在那里中断。

在Chrome中,最大的问题是仅仅给它.focus()是不够的(它一直选择全部文本!)因此,我们将其值设置为自身el.value = el.value;在调用我们的函数之前,并且现在具有了一个输入的把握和位置来使用selectionStart

function setCaretPosition(elemId, caretPos) {
    var el = document.getElementById(elemId);

    el.value = el.value;
    // ^ this is used to not only get "focus", but
    // to make sure we don't have it everything -selected-
    // (it causes an issue in chrome, and having it doesn't hurt any other browser)

    if (el !== null) {

        if (el.createTextRange) {
            var range = el.createTextRange();
            range.move('character', caretPos);
            range.select();
            return true;
        }

        else {
            // (el.selectionStart === 0 added for Firefox bug)
            if (el.selectionStart || el.selectionStart === 0) {
                el.focus();
                el.setSelectionRange(caretPos, caretPos);
                return true;
            }

            else  { // fail city, fortunately this never happens (as far as I've tested) :)
                el.focus();
                return false;
            }
        }
    }
}

@mcpDESIGNS 我正在尝试在文本输入框获得焦点时使用此函数,但是我一无所获。您能否请帮忙使用纯JavaScript应用此函数? - elad.chen
@elad.chen 你是想让它们在用户将焦点放在文本框上时立即定位到文本框的末尾吗? - Mark Pieszak - Trilon.io
@mcpDESIGNS 我想在元素被聚焦时将光标放在字段的开头。请参见这个 jsfiddle.net/KuLTU/3。 - elad.chen
@elad.chen 很抱歉回复晚了!只需在您的search_field_focus函数中将该事件更改为.onclick而不是.onfocus即可。 - Mark Pieszak - Trilon.io
2
我会交换这两行代码。如果 el 为空,el.value = el.value 将会失败,所以这一行应该在 if 语句内部。代码如下:if (el !== null) { el.value = el.value; } - BackSlash

25

我发现了一种容易解决这个问题的方法,已在IE和Chrome中测试过:

function setCaret(elemId, caret)
 {
   var elem = document.getElementById(elemId);
   elem.setSelectionRange(caret, caret);
 }

将文本框的ID和光标位置传递给此函数。


1
简短而优雅。 - Yaniv K.
是的,使用setSelectionRange是我正在寻找的解决方案。位置是以零为基准的,并且将其设置为大于长度的值会将插入符号移动到最后的位置。我通过const len = elem.value.length获取当前长度,并通过elem.setSelectionRange(len,len)将插入符号移动到最后的位置。 - some
是的,使用setSelectionRange是我正在寻找的解决方案。位置是以零为基础的,将其设置为大于长度的值会将插入符号移动到最后的位置。我使用const len = elem.value.length获取当前长度,并通过elem.setSelectionRange(len,len)将插入符号移动到最后的位置。 - undefined

22

我稍微修改了kd7的答案,因为当selectionStart恰好为0时,elem.selectionStart将会被评估为false。

function setCaretPosition(elem, caretPos) {
    var range;

    if (elem.createTextRange) {
        range = elem.createTextRange();
        range.move('character', caretPos);
        range.select();
    } else {
        elem.focus();
        if (elem.selectionStart !== undefined) {
            elem.setSelectionRange(caretPos, caretPos);
        }
    }
}

3

如果您需要聚焦一些文本框,而您唯一的问题是整个文本都被突出显示,而您希望插入符号在文本末尾,则在这种特殊情况下,您可以使用以下技巧:在聚焦后将文本框值设置为自身:

$("#myinputfield").focus().val($("#myinputfield").val());

2
function SetCaretEnd(tID) {
    tID += "";
    if (!tID.startsWith("#")) { tID = "#" + tID; }
    $(tID).focus();
    var t = $(tID).val();
    if (t.length == 0) { return; }
    $(tID).val("");
    $(tID).val(t);
    $(tID).scrollTop($(tID)[0].scrollHeight); }

未捕获的类型错误:对象[object HTMLInputElement]没有startsWith方法。 - bobpaul
1
@bobpaul:tID 应该是元素的 ID,而不是元素对象本身。如果您正在传递元素对象,则可以删除此方法中的前两行,它将正常工作。 - awe

2

HTMLInputElement.setSelectionRange(selectionStart,selectionEnd);

该方法用于在文本输入框中设置选定文本的起始位置和结束位置。其中,selectionStart表示选定文本的起始位置,selectionEnd表示选定文本的结束位置。
// References
var e = document.getElementById( "helloworldinput" );

// Move caret to beginning on focus
e.addEventListener( "focus", function( event )
{
    // References
    var e = event.target;

    // Action
    e.setSelectionRange( 0, 0 );            // Doesn’t work for focus event
    
    window.setTimeout( function()
    {
        e.setSelectionRange( 0, 0 );        // Works
        //e.setSelectionRange( 1, 1 );      // Move caret to second position
        //e.setSelectionRange( 1, 2 );      // Select second character

    }, 0 );

}, false );

浏览器兼容性(仅适用于文本、搜索、网址、电话和密码类型): https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange#Specifications

2
我会将条件修复如下:
function setCaretPosition(elemId, caretPos)
{
 var elem = document.getElementById(elemId);
 if (elem)
 {
  if (typeof elem.createTextRange != 'undefined')
  {
   var range = elem.createTextRange();
   range.move('character', caretPos);
   range.select();
  }
  else
  {
   if (typeof elem.selectionStart != 'undefined')
    elem.selectionStart = caretPos;
   elem.focus();
  }
 }
}

1
<!DOCTYPE html>
<html>
<head>
<title>set caret position</title>
<script type="application/javascript">
//<![CDATA[
window.onload = function ()
{
 setCaret(document.getElementById('input1'), 13, 13)
}

function setCaret(el, st, end)
{
 if (el.setSelectionRange)
 {
  el.focus();
  el.setSelectionRange(st, end);
 }
 else
 {
  if (el.createTextRange)
  {
   range = el.createTextRange();
   range.collapse(true);
   range.moveEnd('character', end);
   range.moveStart('character', st);
   range.select();
  }
 }
}
//]]>
</script>
</head>
<body>

<textarea id="input1" name="input1" rows="10" cols="30">Happy kittens dancing</textarea>

<p>&nbsp;</p>

</body>
</html>

这个什么也不做。 - user16583522

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