jQuery Установить положение курсора в текстовой области
Как установить позицию курсора в текстовом поле с помощью 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);
15 ответов
У меня есть две функции:
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);
Живой пример с обоими textarea
и input
, показывающий использование из jQuery:
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);
}
$("#set-textarea").click(function() {
setCaretToPos($("#the-textarea")[0], 10)
});
$("#set-input").click(function() {
setCaretToPos($("#the-input")[0], 10);
});
<textarea id="the-textarea" cols="40" rows="4">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</textarea>
<br><input type="button" id="set-textarea" value="Set in textarea">
<br><input id="the-input" type="text" size="40" value="Lorem ipsum dolor sit amet, consectetur adipiscing elit">
<br><input type="button" id="set-input" value="Set in input">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
По состоянию на 2016 год тестировался и работал на Chrome, Firefox, IE11, даже на IE8 (см. Последнее здесь; фрагменты стека не поддерживают IE8).
Вот решение 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
Решения здесь правильные, за исключением кода расширения 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;
};
Я нашел решение, которое работает для меня:
$.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;
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();
Это сработало для меня в Safari 5 на Mac OSX, jQuery 1.4:
$("Selector")[elementIx].selectionStart = desiredStartPos;
$("Selector")[elementIx].selectionEnd = desiredEndPos;
Я понимаю, что это очень старая статья, но я подумал, что должен предложить, возможно, более простое решение, чтобы обновить ее, используя только 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), поэтому мне придется отредактировать это в будущем, чтобы убедиться, что часть работает снова. Если у вас есть идея, как это сделать, пожалуйста, прокомментируйте здесь, и я буду рад проверить это. Благодарю.
Установить фокус перед тем, как вставить текст в текстовое поле?
$("#comments").focus();
$("#comments").val(comments);
В IE для перемещения курсора на какую-то позицию этого кода достаточно:
var range = elt.createTextRange();
range.move('character', pos);
range.select();
Это работает для меня в Chrome
$('#input').focus(function() {
setTimeout( function() {
document.getElementById('input').selectionStart = 4;
document.getElementById('input').selectionEnd = 4;
}, 1);
});
Очевидно, вам нужна задержка в микросекунду или больше, потому что обычно пользователь фокусируется на текстовом поле, щелкая мышью по какой-то позиции в текстовом поле (или нажимая клавишу табуляции), которую вы хотите переопределить, поэтому вам придется подождать, пока позиция не станет установить пользователем нажмите и затем измените его.
Просто не забывайте возвращать false сразу после вызова функции, если вы используете клавиши со стрелками, так как в противном случае Chrome обманывает фрак.
{
document.getElementById('moveto3').setSelectionRange(3,3);
return false;
}
Исходя из этого вопроса, ответ не будет работать идеально для ie и opera, когда в текстовой области появится новая строка. В ответе объясняется, как настроить selectionStart, selectionEnd перед вызовом setSelectionRange.
Я попытался настроить Offset из другого вопроса с решением, предложенным @AVProgrammer, и он работает.
function adjustOffset(el, offset) {
/* From https://stackru.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://stackru.com/a/7180862/611741 */
if(this.lengh == 0) return this;
return $(this).setSelection(position, position);
}
$.fn.setSelection = function(selectionStart, selectionEnd) {
/* From https://stackru.com/a/7180862/611741
modified to fit https://stackru.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://stackru.com/a/7180862/611741 */
this.setCursorPosition(this.val().length);
}
Небольшая модификация кода, который я нашел в 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)
Я должен был заставить это работать для 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)
устанавливает смещение и фокусируется на элементе.
Также небольшой совет, если вы бежите $(selector).setCaret(num)
из консоли он вернет console.log, но вы не сможете визуализировать фокус, поскольку он установлен в окне консоли.
Bests; D
Вы можете напрямую изменить прототип, если 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
Как по мне, здесь самый простой способ добавить текст (Tab -> \t) в текстовое поле по положению курсора и сохранить фокус на курсоре:
$('#text').keyup(function () {
var cursor = $('#text').prop('selectionStart');
//if cursot is first in textarea
if (cursor == 0) {
//i will add tab in line
$('#text').val('\t' + $('#text').val());
//here we set the cursor position
$('#text').prop('selectionEnd', 1);
} else {
var value = $('#text').val();
//save the value before cursor current position
var valToCur = value.substring(0, cursor);
//save the value after cursor current position
var valAfter = value.substring(cursor, value.length);
//save the new value with added tab in text
$('#text').val(valToCur + '\t' + valAfter);
//set focus of cursot after insert text (1 = because I add only one symbol)
$('#text').prop('selectionEnd', cursor + 1);
}
});