jQuery Mengatur Posisi Kursor di Area Teks


435

Bagaimana Anda mengatur posisi kursor dalam bidang teks menggunakan jQuery? Saya punya bidang teks dengan konten, dan saya ingin kursor pengguna diposisikan pada offset tertentu ketika mereka fokus pada bidang tersebut. Kode akan terlihat seperti ini:

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

Seperti apa penerapan fungsi setCursorPosition itu? Jika Anda memiliki bidang teks dengan konten abcdefg, panggilan ini akan mengakibatkan kursor diposisikan sebagai berikut: abcd ** | ** efg.

Java memiliki fungsi serupa, setCaretPosition. Apakah ada metode serupa untuk javascript?

Pembaruan: Saya memodifikasi kode CMS agar berfungsi dengan jQuery sebagai berikut:

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)? Anda tahu itu persis sama this.setSelectionRange, hanya lebih lambat dan lebih sulit untuk dibaca, bukan? jQuery benar-benar tidak melakukan apa pun untuk Anda di sini.
bobince

2
Untuk menambahkan komentar @obobince, fungsi harus beralih untuk setiap elemen yang dipilih dan mengembalikannya. Kode yang benar ada dalam jawaban saya.
HRJ

21
@obobince sebenarnya juga tidak sepenuhnya benar. 'ini' bukan node DOM, tetapi objek jQuery. Jadi, $ (this) .get (0) .setSelectionRange sama dengan this.get (0) .setSelectionRange, tidak sama dengan this.setSelectionRange.
Prestaul

$ (ini) [0] lebih cepat dari $ (ini) .get (0)
EminezArtus

Lihatlah tutorial ini untuk solusi lengkap. webdesignpluscode.blogspot.com/2017/05/…
Waqas Ali

Jawaban:


254

Saya memiliki dua fungsi:

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

Kemudian Anda dapat menggunakan setCaretToPos seperti ini:

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

Contoh langsung dengan a textareadan a input, menunjukkan penggunaan dari jQuery:

Pada 2016, diuji dan bekerja di Chrome, Firefox, IE11, bahkan IE8 (lihat yang terakhir di sini ; Cuplikan Stack tidak mendukung IE8).


3
Mengapa runtuh (benar) diperlukan karena Anda akan mengatur akhir dan memulai offset seleksi?
Alexis Wilke

@mareoraft: Bekerja pada textarea(dan input) untuk saya di Chrome, Firefox, IE8, dan IE11.
TJ Crowder

Saya sepertinya tidak bisa melakukan ini dengan skrip saya. Saya memiliki area teks yang kosong pada pemuatan halaman, kemudian diisi oleh javascript saat aplikasi digunakan. Saya ingin tanda sisipan dikembalikan ke 0 sebelum setiap penulisan baru (catatan penggunaan). apakah data dinamis yang menyebabkan masalah bagi saya? jika demikian bagaimana saya bisa mengatasi itu?
Chris

Apa pentingnya 'karakter' string literal? Apakah string spesifik itu perlu digunakan?
Jon Schneider

299

Inilah solusi 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();
        }
    });
};

Dengan ini, Anda bisa melakukannya

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

2
@ Jesse: Entah bagaimana itu terjadi, saya biasanya menggunakan 4. Tetap.
mpen

1
@UberNeet: Diperbarui berdasarkan saran Anda.
mpen

1
@ Ennve: Saya tidak punya salinan IE 5.5 untuk diuji, tapi itu mungkin karena jQuery tidak mendukung IE 5.5 .
mpen

1
@ JaroslavZáruba: Ya. Ini. Tetapi memungkinkan Anda untuk tidak harus menulis selectRange($('.my_input')[0], 3, 5)jika Anda sudah menggunakan jQuery. Lebih lanjut, itu harus bekerja dengan lebih dari satu elemen, jika Anda membutuhkannya, untuk alasan apa pun. Jika Anda ingin yang asli murni, silakan gunakan solusi CMS.
mpen

2
Saya perlu menambahkan $('#elem').focus()terlebih dahulu untuk mendapatkan kursor berkedip muncul.
mareoraft

37

Solusi di sini benar kecuali untuk kode ekstensi jQuery.

Fungsi ekstensi harus beralih pada setiap elemen yang dipilih dan kembali thiske rantai dukungan. Berikut ini yang merupakan versi yang benar:

$.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
Setiap fungsi mengembalikan objek jquery. sehingga Anda benar-benar dapat melakukannya: return this.each(function...)dan menghapus garis mandiri.
jhummel

23

Saya menemukan solusi yang berfungsi untuk saya:

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

Sekarang Anda dapat memindahkan fokus ke akhir elemen apa pun dengan menelepon:

$(element).focusEnd();

Atau Anda menentukan posisi.

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

3
Untuk elemen textarea, perbaikan pada focusEnd adalah menambahkan this.scrollTop(this[0].scrollHeight);, untuk memastikan bahwa textarea digulir untuk membuat titik penyisipan terlihat.
Drew

12

Ini bekerja untuk saya di Safari 5 di Mac OSX, jQuery 1.4:

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

bagi saya itu tidak berfungsi dengan baik dengan akses langsung, tetapi ini bekerja dengan sempurna. $ (myID) .prop ('selectionStart', position); $ (myID) .prop ('selectionEnd', position);
amdan

9

Saya menyadari bahwa ini adalah posting yang sangat lama, tetapi saya berpikir bahwa saya mungkin harus menawarkan solusi yang lebih sederhana untuk memperbaruinya hanya menggunakan 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;
}

Penggunaan untuk menggunakan ctrl-enter untuk menambahkan baris baru (seperti di 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);
    }
});

Saya terbuka untuk kritik. Terima kasih.

PEMBARUAN: Solusi ini tidak memungkinkan fungsionalitas salin dan tempel normal berfungsi (yaitu ctrl-c, ctrl-v), jadi saya harus mengedit ini di masa mendatang untuk memastikan bagian itu berfungsi lagi. Jika Anda memiliki ide bagaimana melakukannya, silakan komentar di sini, dan saya akan dengan senang hati mengujinya. Terima kasih.


7

Di IE untuk memindahkan kursor pada beberapa posisi, kode ini cukup:

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


7

Tetapkan fokus sebelum Anda memasukkan teks ke dalam textarea demikian?

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

6

Ini bekerja untuk saya di chrome

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

Rupanya Anda memerlukan penundaan mikrodetik atau lebih, karena biasanya pengguna fokus pada bidang teks dengan mengklik pada beberapa posisi di bidang teks (atau dengan menekan tab) yang ingin Anda timpa, jadi Anda harus menunggu sampai posisi tersebut diatur oleh pengguna klik lalu ubah.


Penugasan ke properti hanya-baca tidak diperbolehkan dalam mode ketat
Ivan Rubinson

4

Ingatlah untuk mengembalikan false tepat setelah pemanggilan fungsi jika Anda menggunakan tombol panah karena Chrome membelah frack up sebaliknya.

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

2
Ini bukan praktik terbaik return false;. Anda event.preventDefault();malah mau . Jika Anda mengembalikan false, Anda menyiratkan event.stopPropagation()yang tidak selalu diinginkan
Alan H.

4

Berdasarkan pertanyaan ini , jawabannya tidak akan bekerja dengan sempurna untuk ie dan opera ketika ada baris baru di textarea. The jawaban menjelaskan bagaimana untuk menyesuaikan selectionStart, selectionEnd sebelum menelepon setSelectionRange.

Saya telah mencoba AdjustOffset dari pertanyaan lain dengan solusi yang diajukan oleh @AVProgrammer dan berfungsi.

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

Modifikasi kecil pada kode yang saya temukan di bitbucket

Kode sekarang dapat memilih / menyorot dengan titik awal / akhir jika diberi 2 posisi. Diuji dan berfungsi dengan baik di FF / Chrome / IE9 / Opera.

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

Kode tercantum di bawah ini, hanya beberapa baris yang berubah:

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

Berjalan di Chrome 39, IE11, Safari 5.1.7 tetapi tidak di Firefox 34: jsfiddle.net/0t94z82k/6
jbobbins

3

Saya harus membuatnya berfungsi untuk elemen yang dapat diedit dan jQuery dan seseorang mungkin ingin itu siap digunakan:

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

Penggunaan $(selector).getCaret()mengembalikan offset angka dan $(selector).setCaret(num)menetapkan offset dan menetapkan fokus pada elemen.

Juga tip kecil, jika Anda menjalankan $(selector).setCaret(num)dari konsol itu akan mengembalikan konsol.log tetapi Anda tidak akan memvisualisasikan fokus karena didirikan di jendela konsol.

Bests; D


1

Anda dapat langsung mengubah prototipe jika setSelectionRange tidak ada.

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

tautan jsFiddle

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.