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);

Ответ 1

У меня есть две функции:

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>

Ответ 2

Здесь решение 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

Ответ 3

Решения здесь правы, за исключением кода расширения 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

Я нашел решение, которое работает для меня:

$.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.

Ответ 5

Это сработало для меня в Safari 5 на Mac OSX, jQuery 1.4:

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

Ответ 6

Я понимаю, что это очень старый пост, но я подумал, что я должен предложить, возможно, более простое решение для его обновления, используя только 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);
    }
});

Я открыт для критики. Спасибо.

UPDATE: это решение не позволяет работать с нормальной копией и вставкой (т.е. ctrl-c, ctrl-v), поэтому мне нужно будет изменить это в будущем, чтобы убедиться, что эта часть работает снова. Если у вас есть идея, как это сделать, прокомментируйте здесь, и я буду рад проверить это. Спасибо.

Ответ 8

В IE для перемещения курсора на некоторую позицию достаточно этого кода:

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

Ответ 9

Установите фокус, прежде чем вставлять текст в текстовую область?

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

Ответ 10

Это работает для меня в хроме.

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

По-видимому, вам нужна задержка в микросекунду или больше, потому что обычно пользователь фокусируется на текстовом поле, щелкая в какой-либо позиции в текстовом поле (или на вкладке), которое вы хотите переопределить, поэтому вам нужно подождать до позиция устанавливается щелчком пользователя, а затем меняет его.

Ответ 11

Небольшая модификация кода, который я нашел в 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)

Ответ 12

Не забудьте вернуть false сразу после вызова функции, если вы используете клавиши со стрелками, так как Chrome фрикирует в противном случае.

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

Ответ 13

Основываясь на этом question, ответ не будет работать отлично для ie и opera, когда в текстовой области есть новая строка. Ответ объясняет, как настроить selectionStart, selectEnd перед вызовом setSelectionRange.

Я попробовал setupOffset из другого вопроса с помощью решения, предложенного @AVProgrammer, и он работает.

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);
}

Ответ 14

Мне пришлось заставить эту работу работать с доступными для контента элементами и 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

Ответ 15

Вы можете напрямую изменить прототип, если 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 ссылка