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

2
Щоб додати до коментаря @bobince, функція повинна повторити кожен із вибраних елементів і повернути це. Правильний код є моєю відповіддю.
HRJ

21
@bobince насправді теж не зовсім коректно. 'це' не вузол DOM, а об’єкт jQuery. Отже, $ (this) .get (0) .setSelectionRange такий же, як this.get (0) .setSelectionRange, не такий, як this.setSelectionRange.
Prestaul

$ (this) [0] швидше, ніж $ (this) .get (0)
EminezArtus

Перегляньте цей підручник для повного рішення. webdesignpluscode.blogspot.com/2017/05/…
Waqas Ali

Відповіді:


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і з input, показуючи використання jQuery:

Станом на 2016 рік, протестовано та працює в Chrome, Firefox, IE11, навіть IE8 (дивіться, що останній тут ; Сніпкети стека не підтримують IE8).


3
Чому крах (істинний) необхідний, оскільки ви збираєтеся поставити кінець і почати відбір компенсації?
Alexis Wilke

@mareoraft: працює для textareainput) для Chrome, Firefox, IE8 та IE11.
TJ Crowder

Я, здається, не зможу змусити це працювати зі своїм сценарієм. У мене на сторінці завантажується область тексту, яка порожня, потім заповнюється javascript в якості використання програми. Я хочу, щоб карета поверталася до 0 перед кожним новим записом (запис про використання). чи викликають у мене динамічні дані? якщо так, як я міг обійти це?
Кріс

У чому значення буквеного "символу" рядка? Чи потрібно використовувати цей конкретний рядок?
Джон Шнайдер

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. Виправлено.
квітня 1111

1
@UberNeet: оновлено на основі вашої пропозиції.
1313

1
@Enve: У мене немає копії IE 5.5 для тестування, але це, ймовірно, тому, що jQuery не підтримує IE 5.5 .
1313

1
@ JaroslavZáruba: Так. Це є. Але дозволяє вам не писати, selectRange($('.my_input')[0], 3, 5)якщо ви вже використовуєте jQuery. Крім того, він повинен працювати з більш ніж одним елементом, якщо вам це потрібно з будь-якої причини. Якщо ви хочете чисто рідного, будь ласка, використовуйте рішення CMS.
mpen

2
Мені потрібно було додати $('#elem').focus()заздалегідь, щоб відобразити миготливий курсор.
мареофт

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

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
Для елементів текстових областей поліпшення фокусуванняEnd полягає в додаванні this.scrollTop(this[0].scrollHeight);, щоб забезпечити прокручування textarea, щоб зробити точку вставки видимою.
Дрю

12

Це працювало для мене на Safari 5 на Mac OSX, jQuery 1.4:

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

для мене це не працювало нормально з прямим доступом, але це спрацювало чудово. $ (myID) .prop ('selectionStart', позиція); $ (myID) .prop ('selectionEnd', позиція);
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

Це працює для мене в хромі

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

Мабуть, вам потрібна затримка мікросекунди або більше, тому що зазвичай користувач фокусується на текстовому полі, клацнувши на деякій позиції в текстовому полі (або натиснувши вкладку), яку ви хочете змінити, тому вам доведеться почекати, поки позиція буде встановлений користувачем клацання, а потім змінити його.


Призначення властивостей лише для читання заборонено в суворому режимі
Іван Рубінсон

4

Просто не забудьте повернути помилкове відразу після виклику функції, якщо ви використовуєте клавіші зі стрілками, оскільки Chrome виправляє фрейк в іншому випадку.

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

2
Це не найкраща практика return false;. Ви хочете event.preventDefault();замість цього. Якщо ви повернете помилковий, ви маєте на увазі, event.stopPropagation()що не завжди бажано
Алан Х.

4

Виходячи з цього питання , відповідь не буде ідеально підходить для ie і opera, коли в текстовій області з'явиться новий рядок. Відповідь пояснити , як налаштувати SelectionStart, selectionEnd перед викликом setSelectionRange.

Я спробував налаштуватиffOffset з іншого питання з рішенням, запропонованим @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);
}

4

Невелика модифікація коду, яку я знайшов у бітбукеті

Код тепер може вибрати / виділити за допомогою початкової / кінцевої точок, якщо надано 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

3

Мені довелося зробити так, щоб це працювало на змістовні елементи та 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, але ви не візуалізуєте фокус, оскільки він встановлений у вікні консолі.

Звірі; 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 посилання

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.