Bagaimana cara mendapatkan posisi kolom caret (bukan piksel) di textarea, dalam karakter, dari awal?

174

Bagaimana Anda mendapatkan posisi tanda kuret dalam <textarea>menggunakan JavaScript?

Sebagai contoh: This is| a text

Ini harus kembali 7.

Bagaimana Anda mendapatkannya untuk mengembalikan string yang mengelilingi kursor / seleksi?

Misalnya: 'This is', '', ' a text'.

Jika kata "is" disorot, maka itu akan kembali 'This ', 'is', ' a text'.

Gelisah Pengembara
sumber
Lihat pertanyaan ini: stackoverflow.com/questions/164147/… dan jika Anda akan memiliki baris baru, juga catatan tentang itu di sini: stackoverflow.com/questions/235411/…
bobince
1
Jika Anda menggunakan jQuery, Anda dapat menggunakan plugin jquery caret $ ('textarea'). GetSelection ().
Mulai
Menemukan solusi yang bagus di blog.vishalon.net/index.php/... Saya mengujinya di firefox dan chrome, dan berhasil di keduanya. Penulis mengatakan itu bekerja di IE + Opera juga.
pycoder112358
Penggunaan sederhana textarea.selectionStart, textarea. selectionEnd, textarea.setSelectionRange developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement
EAndreyF

Jawaban:

173

Dengan Firefox, Safari (dan peramban berbasis Gecko lainnya) Anda dapat dengan mudah menggunakan textarea.selectionStart, tetapi untuk IE yang tidak berfungsi, jadi Anda harus melakukan sesuatu seperti ini:

function getCaret(node) {
  if (node.selectionStart) {
    return node.selectionStart;
  } else if (!document.selection) {
    return 0;
  }

  var c = "\001",
      sel = document.selection.createRange(),
      dul = sel.duplicate(),
      len = 0;

  dul.moveToElementText(node);
  sel.text = c;
  len = dul.text.indexOf(c);
  sel.moveStart('character',-1);
  sel.text = "";
  return len;
}

( kode lengkap di sini )

Saya juga menyarankan Anda untuk memeriksa Plugin jQuery FieldSelection , ini memungkinkan Anda untuk melakukan itu dan banyak lagi ...

Sunting: Saya benar-benar menerapkan kembali kode di atas:

function getCaret(el) { 
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
        rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    return rc.text.length; 
  }  
  return 0; 
}

Lihat contoh di sini .

CMS
sumber
1
Ini tidak membedakan antara posisi caret ketika caret ditempatkan pada garis kosong. Lihat stackoverflow.com/questions/3053542/…
Tim Down
4
Jawaban ini tidak berurusan dengan masalah baris kosong.
Tim Down
6
Bagaimana saya bisa menggunakan ini untuk div CONTENTEDITABLE?
Muhammet Göktürk Ayan
1
Anda mungkin ingin menulis ulang jawaban ini sedikit, Safari (and other Gecko based browsers)Tampaknya menyiratkan bahwa Safari menggunakan Gecko. Gecko adalah mesin Mozilla; Safari menggunakan WebKit.
Kode Tidak Berguna
1
caret pada posisi 0 akan gagal tes if (el.selectionStart) { return el.selectionStart; }...
okm
57

Diperbarui 5 September 2010

Melihat semua orang sepertinya diarahkan ke sini untuk masalah ini, saya menambahkan jawaban saya ke pertanyaan serupa, yang berisi kode yang sama dengan jawaban ini tetapi dengan latar belakang penuh bagi mereka yang tertarik:

Document.selection.createRange IE tidak termasuk memimpin atau mengikuti baris kosong

Untuk menghitung trailing line break sangat rumit di IE, dan saya belum melihat solusi yang melakukan ini dengan benar, termasuk jawaban lain untuk pertanyaan ini. Namun dimungkinkan, menggunakan fungsi berikut, yang akan mengembalikan Anda awal dan akhir seleksi (yang sama dalam kasus tanda sisipan) dalam suatu <textarea>atau teks <input>.

Perhatikan bahwa textarea harus memiliki fokus agar fungsi ini berfungsi dengan baik di IE. Jika ragu, hubungi metode textarea focus()terlebih dahulu.

function getInputSelection(el) {
    var start = 0, end = 0, normalizedValue, range,
        textInputRange, len, endRange;

    if (typeof el.selectionStart == "number" && typeof el.selectionEnd == "number") {
        start = el.selectionStart;
        end = el.selectionEnd;
    } else {
        range = document.selection.createRange();

        if (range && range.parentElement() == el) {
            len = el.value.length;
            normalizedValue = el.value.replace(/\r\n/g, "\n");

            // Create a working TextRange that lives only in the input
            textInputRange = el.createTextRange();
            textInputRange.moveToBookmark(range.getBookmark());

            // Check if the start and end of the selection are at the very end
            // of the input, since moveStart/moveEnd doesn't return what we want
            // in those cases
            endRange = el.createTextRange();
            endRange.collapse(false);

            if (textInputRange.compareEndPoints("StartToEnd", endRange) > -1) {
                start = end = len;
            } else {
                start = -textInputRange.moveStart("character", -len);
                start += normalizedValue.slice(0, start).split("\n").length - 1;

                if (textInputRange.compareEndPoints("EndToEnd", endRange) > -1) {
                    end = len;
                } else {
                    end = -textInputRange.moveEnd("character", -len);
                    end += normalizedValue.slice(0, end).split("\n").length - 1;
                }
            }
        }
    }

    return {
        start: start,
        end: end
    };
}
Tim Down
sumber
Maaf tapi apa artinya ' range && range.parentElement () '?
sergzach
Ada masalah jika kita ingin mendapatkan posisi tanda sisipan di IE (jika pilihan kosong). Dalam hal ini ia mengembalikan 0 sebagai awal dan panjang string sebagai akhir (jika kita menggunakan true alih-alih range && range.parentElement () == el ).
sergzach
@ergergach: Ada di range && range.parentElement() == elsana untuk menguji apakah seleksi ada di dalam textarea dan diperlukan. Tidak ada masalah dengan fungsi mendapatkan posisi caret selama textarea memiliki fokus . Jika tidak yakin, panggil metode textarea focus()sebelum menelepon getInputSelection(). Saya akan menambahkan catatan pada jawabannya.
Tim Down
1
@Tim: Saat mengklik elemen div untuk mengungkapkan pilihan, "mulai" dan "akhir" selalu sama.
Misha Moroshko
3
@Misha: Itu bukan kesalahan fungsi: itulah yang sebenarnya dipilih pada saat fungsi dijalankan. Anda dapat melihatnya secara visual setelah mengabaikan kotak peringatan. Seperti yang saya sebutkan dalam jawaban saya untuk pertanyaan terakhir Anda, dua kemungkinan workarounds menggunakan mousedownevent atau menambahkan unselectable="on"ke <div>elemen.
Tim Down
3

Saya memodifikasi fungsi di atas menjadi akun carriage return di IE. Ini belum diuji tetapi saya melakukan sesuatu yang mirip dengan itu dalam kode saya sehingga harus bisa dikerjakan.

function getCaret(el) {
  if (el.selectionStart) { 
    return el.selectionStart; 
  } else if (document.selection) { 
    el.focus(); 

    var r = document.selection.createRange(); 
    if (r == null) { 
      return 0; 
    } 

    var re = el.createTextRange(), 
    rc = re.duplicate(); 
    re.moveToBookmark(r.getBookmark()); 
    rc.setEndPoint('EndToStart', re); 

    var add_newlines = 0;
    for (var i=0; i<rc.text.length; i++) {
      if (rc.text.substr(i, 2) == '\r\n') {
        add_newlines += 2;
        i++;
      }
    }

    //return rc.text.length + add_newlines;

    //We need to substract the no. of lines
    return rc.text.length - add_newlines; 
  }  
  return 0; 
}
menandai
sumber
2

Jika Anda tidak harus mendukung IE, Anda dapat menggunakan selectionStartdan selectionEndatribut textarea.

Untuk mendapatkan posisi caret gunakan saja selectionStart:

function getCaretPosition(textarea) {
  return textarea.selectionStart
}

Untuk mendapatkan string seputar seleksi, gunakan kode berikut:

function getSurroundingSelection(textarea) {
  return [textarea.value.substring(0, textarea.selectionStart)
         ,textarea.value.substring(textarea.selectionStart, textarea.selectionEnd)
         ,textarea.value.substring(textarea.selectionEnd, textarea.value.length)]
}

Demo di JSFiddle .

Lihat juga dokumen HTMLTextAreaElement .

Michał Perłakowski
sumber