jQuery在文本区域中设置光标位置


435

如何使用jQuery在文本字段中设置光标位置?我有一个带有内容的文本字段,我希望用户将光标放在该字段上时将光标定位在某个偏移处。该代码应该看起来像这样:

$('#input').focus(function() {
  $(this).setCursorPosition(4);
});

该setCursorPosition函数的实现是什么样的?如果您的文本字段的内容为abcdefg,则此调用将导致光标的定位如下:abcd ** | ** efg。

Java具有类似的功能setCaretPosition。javascript是否存在类似的方法?

更新:我修改了CMS的代码以与jQuery配合使用,如下所示:

new function($) {
  $.fn.setCursorPosition = function(pos) {
    if (this.setSelectionRange) {
      this.setSelectionRange(pos, pos);
    } else if (this.createTextRange) {
      var range = this.createTextRange();
      range.collapse(true);
      if(pos < 0) {
        pos = $(this).val().length + pos;
      }
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  }
}(jQuery);

78
$(this).get(0).setSelectionRange)?您确实知道这与完全一样this.setSelectionRange,只是阅读起来越来越慢,对吧?jQuery在这里实际上没有为您做任何事情。
bobince 2010年

2
要添加到@bobince注释中,该函数应针对每个选定的元素进行迭代,并返回该元素。正确的代码在我的答案中。
HRJ 2010年

21
@bobince实际上也不是很正确。“这”不是DOM节点,而是jQuery对象。因此,$(this..get(0).setSelectionRange与this.get(0).setSelectionRange相同,与this.setSelectionRange不同。
Prestaul 2010年

$(this)[0]比$(this).get(0)快
EminezArtus 2014年

查看本教程以获取完整的解决方案。webdesignpluscode.blogspot.com/2017/05/...
瓦卡斯·阿里

Answers:


254

我有两个功能:

function setSelectionRange(input, selectionStart, selectionEnd) {
  if (input.setSelectionRange) {
    input.focus();
    input.setSelectionRange(selectionStart, selectionEnd);
  }
  else if (input.createTextRange) {
    var range = input.createTextRange();
    range.collapse(true);
    range.moveEnd('character', selectionEnd);
    range.moveStart('character', selectionStart);
    range.select();
  }
}

function setCaretToPos (input, pos) {
  setSelectionRange(input, pos, pos);
}

然后,您可以像这样使用setCaretToPos:

setCaretToPos(document.getElementById("YOURINPUT"), 4);

带有a textarea和an的实时示例input,显示了jQuery的用法:

截至2016年,测试并在Chrome,火狐,IE11,甚至IE8的工作(见去年在这里 ;栈片断不支持IE8)。


3
既然要设置结束和开始选择偏移量,为什么要收起(true)?
Alexis Wilke 2013年

@mareoraft:在Chrome,Firefox,IE8和IE11 上textarea(和input)为我工作。
TJ Crowder

我似乎无法使它与我的脚本一起使用。我有一个文本区域,页面加载时为空,然后在使用该应用程序时由javascript填充。我希望插入符号在每次新写入(使用记录)之前都返回0。是动态数据导致我出现问题吗?如果是这样,我该如何解决?
克里斯(Chris

字符串文字“ character”的意义是什么?是否需要使用特定的字符串?
乔恩·施耐德

299

这是一个jQuery解决方案:

$.fn.selectRange = function(start, end) {
    if(end === undefined) {
        end = start;
    }
    return this.each(function() {
        if('selectionStart' in this) {
            this.selectionStart = start;
            this.selectionEnd = end;
        } else if(this.setSelectionRange) {
            this.setSelectionRange(start, end);
        } else if(this.createTextRange) {
            var range = this.createTextRange();
            range.collapse(true);
            range.moveEnd('character', end);
            range.moveStart('character', start);
            range.select();
        }
    });
};

有了这个,你可以做

$('#elem').selectRange(3,5); // select a range of text
$('#elem').selectRange(3); // set cursor position

2
@杰西:邓诺是怎么回事,我通常使用4。固定。
mpen 2011年

1
@UberNeet:根据您的建议进行了更新。
mpen

1
@Enve:我没有要测试的IE 5.5副本,但这很可能是因为jQuery不支持IE 5.5
mpen

1
@JaroslavZáruba:是的。它是。但是,如果您已经在使用jQuery,则无需编写selectRange($('.my_input')[0], 3, 5)。此外,无论出于何种原因,如果需要,它应使用多个元素。如果您要使用纯本机,请使用CMS解决方案。
mpen 2014年

2
我需要$('#elem').focus()预先添加才能使闪烁的光标出现。
mareoraft 2015年

37

除了jQuery扩展代码,这里的解决方案都是正确的。

扩展功能应该遍历每个选定的元素,并返回this到支持链接。这是 一个正确的版本:

$.fn.setCursorPosition = function(pos) {
  this.each(function(index, elem) {
    if (elem.setSelectionRange) {
      elem.setSelectionRange(pos, pos);
    } else if (elem.createTextRange) {
      var range = elem.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos);
      range.moveStart('character', pos);
      range.select();
    }
  });
  return this;
};

4
每个函数返回jquery对象。因此您实际上可以执行以下操作:return this.each(function...)并删除独立行。
jhummel 2014年

23

我找到了适合我的解决方案:

$.fn.setCursorPosition = function(position){
    if(this.length == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    if(this.length == 0) return this;
    var input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    this.setCursorPosition(this.val().length);
            return this;
}

现在,您可以通过调用将焦点移到任何元素的末尾:

$(element).focusEnd();

或者您指定位置。

$(element).setCursorPosition(3); // This will focus on the third character.

3
对于textarea元素,对focusEnd的改进是添加this.scrollTop(this[0].scrollHeight);,以确保滚动textarea以使插入点可见。
2015年

12

这对我在Mac OSX上的Safari 5,jQuery 1.4上有效:

$("Selector")[elementIx].selectionStart = desiredStartPos; 
$("Selector")[elementIx].selectionEnd = desiredEndPos;

对我来说,直接访问不能很好地工作,但这确实很不错。$(myID).prop('selectionStart',position); $(myID).prop('selectionEnd',position);
amdan

9

我确实意识到这是一篇非常老的文章,但我认为我应该提供一个也许更简单的解决方案,以仅使用jQuery对其进行更新。

function getTextCursorPosition(ele) {   
    return ele.prop("selectionStart");
}

function setTextCursorPosition(ele,pos) {
    ele.prop("selectionStart", pos + 1);
    ele.prop("selectionEnd", pos + 1);
}

function insertNewLine(text,cursorPos) {
    var firstSlice = text.slice(0,cursorPos);
    var secondSlice = text.slice(cursorPos);

    var new_text = [firstSlice,"\n",secondSlice].join('');

    return new_text;
}

使用ctrl-enter添加新行的用法(例如在Facebook中):

$('textarea').on('keypress',function(e){
    if (e.keyCode == 13 && !e.ctrlKey) {
        e.preventDefault();
        //do something special here with just pressing Enter
    }else if (e.ctrlKey){
        //If the ctrl key was pressed with the Enter key,
        //then enter a new line break into the text
        var cursorPos = getTextCursorPosition($(this));                

        $(this).val(insertNewLine($(this).val(), cursorPos));
        setTextCursorPosition($(this), cursorPos);
    }
});

我愿意接受批评。谢谢。

更新:此解决方案不允许正常的复制和粘贴功能(即ctrl-c,ctrl-v)起作用,因此以后我将必须对其进行编辑以确保该部分再次起作用。如果您有想法,请在此处评论,我们将很乐意对其进行测试。谢谢。


7

在IE中将光标移动到某个位置,此代码就足够了:

var range = elt.createTextRange();
range.move('character', pos);
range.select();


7

在将文本插入到文本区域之前设置焦点吗?

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

6

这对我适用于Chrome

$('#input').focus(function() {
    setTimeout( function() {
        document.getElementById('input').selectionStart = 4;
        document.getElementById('input').selectionEnd = 4;
    }, 1);
});

显然,您需要延迟一微秒或更长的时间,因为通常用户会通过单击要覆盖的文本字段中的某个位置(或单击选项卡)来关注文本字段,因此必须等到该位置由用户设置,然后单击更改。


在严格模式下,不允许分配只读属性
Ivan Rubinson

4

请记住,如果您使用的是箭头键,请在函数调用后立即返回false,否则Chrome会加剧这种情况。

{
    document.getElementById('moveto3').setSelectionRange(3,3);
    return false;
}

2
并非最佳做法return false;。您想要event.preventDefault();代替。如果返回false,则表示event.stopPropagation()这并不总是令人满意
Alan H.

4

基于此问题,当文本区域中有新行时,答案将不适用于ie和opera。的回答解释了如何调用setSelectionRange之前调整selectionStart,选定结束。

我已经尝试了@AVProgrammer提出的解决方案中另一个问题的AdjustOffset,它可以工作。

function adjustOffset(el, offset) {
    /* From https://stackoverflow.com/a/8928945/611741 */
    var val = el.value, newOffset = offset;
    if (val.indexOf("\r\n") > -1) {
        var matches = val.replace(/\r\n/g, "\n").slice(0, offset).match(/\n/g);
        newOffset += matches ? matches.length : 0;
    }
    return newOffset;
}

$.fn.setCursorPosition = function(position){
    /* From https://stackoverflow.com/a/7180862/611741 */
    if(this.lengh == 0) return this;
    return $(this).setSelection(position, position);
}

$.fn.setSelection = function(selectionStart, selectionEnd) {
    /* From https://stackoverflow.com/a/7180862/611741 
       modified to fit https://stackoverflow.com/a/8928945/611741 */
    if(this.lengh == 0) return this;
    input = this[0];

    if (input.createTextRange) {
        var range = input.createTextRange();
        range.collapse(true);
        range.moveEnd('character', selectionEnd);
        range.moveStart('character', selectionStart);
        range.select();
    } else if (input.setSelectionRange) {
        input.focus();
        selectionStart = adjustOffset(input, selectionStart);
        selectionEnd = adjustOffset(input, selectionEnd);
        input.setSelectionRange(selectionStart, selectionEnd);
    }

    return this;
}

$.fn.focusEnd = function(){
    /* From https://stackoverflow.com/a/7180862/611741 */
    this.setCursorPosition(this.val().length);
}

4

对我在bitbucket中找到的代码进行小的修改

如果给定2个位置,代码现在可以选择/突出显示起点/终点。经过测试,在FF / Chrome / IE9 / Opera中运行正常。

$('#field').caret(1, 9);

下面列出了代码,仅更改了几行:

(function($) {
  $.fn.caret = function(pos) {
    var target = this[0];
    if (arguments.length == 0) { //get
      if (target.selectionStart) { //DOM
        var pos = target.selectionStart;
        return pos > 0 ? pos : 0;
      }
      else if (target.createTextRange) { //IE
        target.focus();
        var range = document.selection.createRange();
        if (range == null)
            return '0';
        var re = target.createTextRange();
        var rc = re.duplicate();
        re.moveToBookmark(range.getBookmark());
        rc.setEndPoint('EndToStart', re);
        return rc.text.length;
      }
      else return 0;
    }

    //set
    var pos_start = pos;
    var pos_end = pos;

    if (arguments.length > 1) {
        pos_end = arguments[1];
    }

    if (target.setSelectionRange) //DOM
      target.setSelectionRange(pos_start, pos_end);
    else if (target.createTextRange) { //IE
      var range = target.createTextRange();
      range.collapse(true);
      range.moveEnd('character', pos_end);
      range.moveStart('character', pos_start);
      range.select();
    }
  }
})(jQuery)

在Chrome 39,IE11,Safari 5.1.7中运行,但在Firefox 34中未运行: jsfiddle.net/0t94z82k/6
jbobbins 2014年

3

我必须使此内容适用于contenteditable元素和jQuery,并让有人想立即使用它:

$.fn.getCaret = function(n) {
    var d = $(this)[0];
    var s, r;
    r = document.createRange();
    r.selectNodeContents(d);
    s = window.getSelection();
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return s.anchorOffset;
};

$.fn.setCaret = function(n) {
    var d = $(this)[0];
    d.focus();
    var r = document.createRange();
    var s = window.getSelection();
    r.setStart(d.childNodes[0], n);
    r.collapse(true);
    s.removeAllRanges();
    s.addRange(r);
    console.log('position: '+s.anchorOffset+' of '+s.anchorNode.textContent.length);
    return this;
};

用法$(selector).getCaret()返回数字偏移量,并$(selector).setCaret(num)建立offset并将焦点设置在element上。

还有一个小技巧,如果您$(selector).setCaret(num)从控制台运行,它将返回console.log,但是由于焦点是在控制台窗口中建立的,因此您将无法看到焦点。

最好的


1

如果setSelectionRange不存在,则可以直接更改原型。

(function() {
    if (!HTMLInputElement.prototype.setSelectionRange) {
        HTMLInputElement.prototype.setSelectionRange = function(start, end) {
            if (this.createTextRange) {
                var range = this.createTextRange();
                this.collapse(true);
                this.moveEnd('character', end);
                this.moveStart('character', start);
                this.select();
            }
        }
    }
})();
document.getElementById("input_tag").setSelectionRange(6, 7);

jsFiddle链接

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.