jQuery Установить положение курсора в текстовой области

436

Как вы устанавливаете позицию курсора в текстовом поле с помощью 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 здесь буквально ничего не делает для вас.
  • 2
    Чтобы добавить комментарий @bobince, функция должна выполнить итерацию для каждого из выбранных элементов и вернуть ее. Правильный код в моем ответе.
Показать ещё 3 комментария
Теги:
textfield

15 ответов

238
Лучший ответ

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

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

  • 3
    Зачем нужно свернуть (true), так как вы собираетесь установить конец и начать смещения выбора?
  • 1
    Это решение работает только для элементов <input> .
Показать ещё 3 комментария
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
    @Jesse: Не знаю, как это произошло, я обычно использую 4. Исправлено.
  • 3
    @vsync: у меня работает в хроме. jsfiddle.net/mnbayazit/WpqsN
Показать ещё 11 комментариев
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;
};
  • 3
    Каждая функция возвращает объект jquery. так что вы можете сделать: return this.each(function...) и удалить отдельную строку.
20

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

$.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();
  • 3
    Для элементов textarea, улучшением focusEnd является добавление this.scrollTop(this[0].scrollHeight); , чтобы прокрутить текстовую область, чтобы сделать видимой точку вставки.
9

Это сработало для меня в 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), поэтому мне нужно будет изменить это в будущем, чтобы убедиться, что эта часть работает снова. Если у вас есть идея, как это сделать, прокомментируйте здесь, и я буду рад проверить это. Спасибо.

6

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

$("#comments").focus();
$("#comments").val(comments);
  • 0
    У меня не работает (Firefox на OSX)
6

Я использую это: http://plugins.jquery.com/project/jCaret

  • 6
    Плагин не работает с IE7 / IE8 :(
5

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

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

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

  • 0
    Назначение свойств только для чтения в строгом режиме запрещено
5

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

var range = elt.createTextRange();
range.move('character', pos);
range.select();
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)
  • 0
    Работает в Chrome 39, IE11, Safari 5.1.7, но не в Firefox 34: jsfiddle.net/0t94z82k/6
  • 0
    вот один с многострочным текстом: jsfiddle.net/0t94z82k/8
3

Основываясь на этом 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);
}
2

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

{
    document.getElementById('moveto3').setSelectionRange(3,3);
    return false;
}
  • 2
    Не стоит return false; , Вы хотите event.preventDefault(); вместо. Если вы возвращаете false, вы подразумеваете event.stopPropagation() что не всегда желательно
1

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

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 ссылка

Ещё вопросы

Сообщество Overcoder
Наверх
Меню