Bagaimana cara memasukkan teks ke dalam area teks pada posisi kursor saat ini?


126

Saya ingin membuat fungsi sederhana yang menambahkan teks ke dalam area teks pada posisi kursor pengguna. Itu harus menjadi fungsi yang bersih. Hanya dasar-dasarnya. Saya bisa mencari tahu sisanya.



2
Lihatlah jawaban ini sudah diposting: stackoverflow.com/questions/4456545/…
John Culviner



Jika Anda mencari modul sederhana dengan dukungan undo, coba sisipkan-teks-area teks . Jika Anda membutuhkan dukungan IE8 +, coba paket insert-text-at-cursor .
fregante

Jawaban:


117
function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
}

19
untuk memperbaiki "kehilangan posisi tanda sisipan": tambahkan baris ini sebelumnya} else { myField.selectionStart = startPos + myValue.length; myField.selectionEnd = startPos + myValue.length;
pengguna340140

10
Terima kasih Rab untuk jawabannya dan @ user340140 untuk perbaikannya. Berikut adalah contoh yang berfungsi .
Znarkus

@ user340140, perbaikan "potensi tanda sisipan yang hilang", hanya berfungsi jika saya memberikan fokus pada masukan tepat sebelum baris yang Anda sarankan. Tampaknya tidak mungkin untuk mengubah pilihan pada bidang yang tidak fokus, setidaknya di Chrome (versi 62.0 saat ini)
Jette

Ada masalah kecil dengan kode ini: selectionStartadalah nilai numerik, dan karenanya harus dibandingkan dengan 0dan tidak '0', dan mungkin harus menggunakan===
Herohtar

82

Cuplikan ini dapat membantu Anda dalam beberapa baris jQuery 1.9+: http://jsfiddle.net/4MBUG/2/

$('input[type=button]').on('click', function() {
    var cursorPos = $('#text').prop('selectionStart');
    var v = $('#text').val();
    var textBefore = v.substring(0,  cursorPos);
    var textAfter  = v.substring(cursorPos, v.length);

    $('#text').val(textBefore + $(this).val() + textAfter);
});

Bagus! Juga bekerja dengan 1.6 dengan sedikit modifikasi.
Șerban Ghiță

1
Tapi itu tidak bisa menggantikan teks yang dipilih
Sergey Goliney

@mparkuk: masih menderita masalah "kehilangan posisi tanda sisipan" yang disebutkan di atas oleh pengguna340140. (Maaf, saya harus memperbaikinya, tetapi saya kehabisan waktu.)
jbobbins

4
Terima kasih telah menyediakan biola yang berfungsi. Saya telah memperbaruinya untuk juga mengatur ulang posisi tanda sisipan dan menjadikannya plugin jquery: jsfiddle.net/70gqn153
freedomn-m

Ini berfungsi tetapi kursor berakhir di lokasi yang salah.
AndroidDev

36

Demi Javascript yang tepat

HTMLTextAreaElement.prototype.insertAtCaret = function (text) {
  text = text || '';
  if (document.selection) {
    // IE
    this.focus();
    var sel = document.selection.createRange();
    sel.text = text;
  } else if (this.selectionStart || this.selectionStart === 0) {
    // Others
    var startPos = this.selectionStart;
    var endPos = this.selectionEnd;
    this.value = this.value.substring(0, startPos) +
      text +
      this.value.substring(endPos, this.value.length);
    this.selectionStart = startPos + text.length;
    this.selectionEnd = startPos + text.length;
  } else {
    this.value += text;
  }
};

ekstensi yang sangat bagus! bekerja seperti yang diharapkan. Terima kasih!
Martin Johansson

Solusi terbaik! Terima kasih
Dima Melnik

4
Bukan ide yang baik untuk memperluas prototipe objek yang tidak Anda miliki. Jadikan saja sebagai fungsi biasa dan berfungsi dengan baik.
fregante

Ini menghapus buffer undo untuk elemen edit setelah pengaturan this.value = .... Apakah ada cara untuk melestarikannya?
c00000fd

19

Jawaban baru:

https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText

Saya tidak yakin tentang dukungan browser untuk ini.

Diuji di Chrome 81.

function typeInTextarea(newText, el = document.activeElement) {
  const [start, end] = [el.selectionStart, el.selectionEnd];
  el.setRangeText(newText, start, end, 'select');
}

document.getElementById("input").onkeydown = e => {
  if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>
<div>It'll replace a selection with the given text.</div>

Jawaban lama:

Modifikasi JS murni dari jawaban Erik Pukinskis:

function typeInTextarea(newText, el = document.activeElement) {
  const start = el.selectionStart
  const end = el.selectionEnd
  const text = el.value
  const before = text.substring(0, start)
  const after  = text.substring(end, text.length)
  el.value = (before + newText + after)
  el.selectionStart = el.selectionEnd = start + newText.length
  el.focus()
}

document.getElementById("input").onkeydown = e => {
  if (e.key === "Enter") typeInTextarea("lol");
}
<input id="input" />
<br/><br/>
<div>Press Enter to insert "lol" at caret.</div>

Diuji di Chrome 47, 81, dan Firefox 76.

Jika Anda ingin mengubah nilai teks yang saat ini dipilih saat Anda mengetik di bidang yang sama (untuk pelengkapan otomatis atau efek serupa), teruskan document.activeElement sebagai parameter pertama.

Ini bukan cara paling elegan untuk melakukan ini, tetapi cukup sederhana.

Contoh penggunaan:

typeInTextarea('hello');
typeInTextarea('haha', document.getElementById('some-id'));

Anda tidak menutup baris dengan >>; <<
Phoenix

4
@Phoenix titik koma adalah opsional dalam Javascript. Bekerja tanpa mereka juga. Meskipun, Anda dapat mengedit dalam titik koma jika Anda mau. Bukan masalah besar.
Jayant Bhawal

3
Saya membuat demo di JSFiddle. Ia juga bekerja menggunakan Version 54.0.2813.0 canary (64-bit), yang pada dasarnya adalah Chrome Canary 54.0.2813.0. Akhirnya, jika Anda ingin memasukkannya ke dalam kotak teks berdasarkan ID, gunakan document.getElementById('insertyourIDhere')di tempat elfungsi.
haykam

Bagian mana dari jawaban saya yang bukan JS "murni"? Apakah saya lupa C ++ di sana?
Erik Aigner

2
Hai @ErikAigner! Sayangnya, saya tidak menyadari pertanyaan ini dijawab oleh dua orang Erik. Maksud saya Erik Pukinskis. Saya akan memperbarui jawaban untuk lebih mencerminkan itu.
Jayant Bhawal

15

Solusi sederhana yang berfungsi di firefox, chrome, opera, safari, dan edge, tetapi mungkin tidak berfungsi di browser IE lama.

  var target = document.getElementById("mytextarea_id")

  if (target.setRangeText) {
     //if setRangeText function is supported by current browser
     target.setRangeText(data)
  } else {
    target.focus()
    document.execCommand('insertText', false /*no UI*/, data);
  }
}

setRangeTextfungsi memungkinkan Anda untuk mengganti pilihan saat ini dengan teks yang disediakan atau jika tidak ada pilihan maka masukkan teks pada posisi kursor. Ini hanya didukung oleh firefox sejauh yang saya tahu.

Untuk browser lain ada perintah "insertText" yang hanya mempengaruhi elemen html yang saat ini difokuskan dan memiliki perilaku yang sama seperti setRangeText

Terinspirasi sebagian oleh artikel ini


Ini hampir benar. Artikel yang Anda tautkan, menawarkan solusi lengkap sebagai satu paket: sisipkan-teks-di-kursor . Namun saya lebih suka execCommandkarena mendukung undodan membuat insert-text-textarea . Tidak ada dukungan IE tetapi lebih kecil
fregante

1
Sayangnya, execCommanddianggap usang oleh MDN: developer.mozilla.org/en-US/docs/Web/API/Document/execCommand Saya tidak tahu mengapa, ini tampaknya sangat berguna!
Richard

1
Ya, execCommand digunakan untuk browser lain, untuk firefox fungsi setRangeText digunakan sebagai gantinya.
Ramast

Ramast, bukan itu yang dilakukan kode Anda. Ini akan menggunakan setRangeText daripada execCommand untuk browser apa pun yang mendefinisikannya (sebagian besar). Untuk perilaku yang Anda gambarkan, Anda perlu memanggil document.execCommand terlebih dahulu, lalu periksa nilai yang dikembalikan. Jika salah, gunakan target.setRangeText.
Jools

@ Jools jika setRangeText didukung, mengapa tidak menggunakannya sebagai ganti execCommand? Mengapa saya perlu mencoba execCommand terlebih dahulu?
Ramast

10

Jawaban Rab berfungsi dengan baik, tetapi tidak untuk Microsoft Edge, jadi saya menambahkan adaptasi kecil untuk Edge juga:

https://jsfiddle.net/et9borp4/

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 

      myField.value = myField.value.substring(0, startPos)+ myValue 
             + myField.value.substring(endPos, myField.value.length); 

      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
}

9

Saya suka javascript sederhana, dan saya biasanya memiliki jQuery. Inilah yang saya dapatkan, berdasarkan mparkuk :

function typeInTextarea(el, newText) {
  var start = el.prop("selectionStart")
  var end = el.prop("selectionEnd")
  var text = el.val()
  var before = text.substring(0, start)
  var after  = text.substring(end, text.length)
  el.val(before + newText + after)
  el[0].selectionStart = el[0].selectionEnd = start + newText.length
  el.focus()
}

$("button").on("click", function() {
  typeInTextarea($("textarea"), "some text")
  return false
})

Berikut demonya: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101


6

function insertAtCaret(text) {
  const textarea = document.querySelector('textarea')
  textarea.setRangeText(
    text,
    textarea.selectionStart,
    textarea.selectionEnd,
    'end'
  )
}

setInterval(() => insertAtCaret('Hello'), 3000)
<textarea cols="60">Stack Overflow Stack Exchange Starbucks Coffee</textarea>

4

Jika pengguna tidak menyentuh input setelah teks dimasukkan, peristiwa 'input' tidak pernah dipicu, dan atribut nilai tidak akan mencerminkan perubahan. Oleh karena itu, penting untuk memicu peristiwa masukan setelah memasukkan teks secara terprogram. Memfokuskan pada bidang saja tidak cukup.

Berikut ini adalah salinan jawaban Snorvarg dengan pemicu masukan di akhir:

function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        myField.focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    // Microsoft Edge
    else if(window.navigator.userAgent.indexOf("Edge") > -1) {
      var startPos = myField.selectionStart; 
      var endPos = myField.selectionEnd; 

      myField.value = myField.value.substring(0, startPos)+ myValue 
             + myField.value.substring(endPos, myField.value.length); 

      var pos = startPos + myValue.length;
      myField.focus();
      myField.setSelectionRange(pos, pos);
    }
    //MOZILLA and others
    else if (myField.selectionStart || myField.selectionStart == '0') {
        var startPos = myField.selectionStart;
        var endPos = myField.selectionEnd;
        myField.value = myField.value.substring(0, startPos)
            + myValue
            + myField.value.substring(endPos, myField.value.length);
    } else {
        myField.value += myValue;
    }
    triggerEvent(myField,'input');
}

function triggerEvent(el, type){
  if ('createEvent' in document) {
    // modern browsers, IE9+
    var e = document.createEvent('HTMLEvents');
    e.initEvent(type, false, true);
    el.dispatchEvent(e);
  } else {
    // IE 8
    var e = document.createEventObject();
    e.eventType = type;
    el.fireEvent('on'+e.eventType, e);
  }
}

Kredit ke plainjs.com untuk fungsi triggerEvent

Selengkapnya tentang acara oninput di w3schools.com

Saya menemukan ini saat membuat pemetik emoji untuk obrolan. Jika pengguna hanya memilih beberapa emoji dan menekan tombol "kirim", bidang input tidak akan pernah disentuh oleh pengguna. Saat memeriksa atribut value, kolom tersebut selalu kosong, meskipun unicode emoji yang dimasukkan terlihat di kolom input. Ternyata jika pengguna tidak menyentuh bidang, peristiwa 'input' tidak pernah diaktifkan dan solusinya adalah memicunya seperti ini. Butuh waktu cukup lama untuk memikirkan yang satu ini ... semoga bisa menghemat waktu.


0

Memposting fungsi yang dimodifikasi untuk referensi sendiri. Contoh ini menyisipkan item yang dipilih dari <select>objek dan meletakkan tanda sisipan di antara tag:

//Inserts a choicebox selected element into target by id
function insertTag(choicebox,id) {
    var ta=document.getElementById(id)
    ta.focus()
    var ss=ta.selectionStart
    var se=ta.selectionEnd
    ta.value=ta.value.substring(0,ss)+'<'+choicebox.value+'>'+'</'+choicebox.value+'>'+ta.value.substring(se,ta.value.length)
    ta.setSelectionRange(ss+choicebox.value.length+2,ss+choicebox.value.length+2)
}

0
 /**
 * Usage "foo baz".insertInside(4, 0, "bar ") ==> "foo bar baz"
 */
String.prototype.insertInside = function(start, delCount, newSubStr) {
    return this.slice(0, start) + newSubStr + this.slice(start + Math.abs(delCount));
};


 $('textarea').bind("keydown keypress", function (event) {
   var val = $(this).val();
   var indexOf = $(this).prop('selectionStart');
   if(event.which === 13) {
       val = val.insertInside(indexOf, 0,  "<br>\n");
       $(this).val(val);
       $(this).focus();
    }
})

Meskipun ini mungkin menjawab pertanyaan, lebih baik menjelaskan bagian penting dari jawaban dan mungkin apa masalah dengan kode OPs.
pirho

0

Kode di bawah ini adalah adaptasi TypeScript dari paket https://github.com/grassator/insert-text-at-cursor oleh Dmitriy Kubyshkin.


/**
 * Inserts the given text at the cursor. If the element contains a selection, the selection
 * will be replaced by the text.
 */
export function insertText(input: HTMLTextAreaElement | HTMLInputElement, text: string) {
  // Most of the used APIs only work with the field selected
  input.focus();

  // IE 8-10
  if ((document as any).selection) {
    const ieRange = (document as any).selection.createRange();
    ieRange.text = text;

    // Move cursor after the inserted text
    ieRange.collapse(false /* to the end */);
    ieRange.select();

    return;
  }

  // Webkit + Edge
  const isSuccess = document.execCommand("insertText", false, text);
  if (!isSuccess) {
    const start = input.selectionStart;
    const end = input.selectionEnd;
    // Firefox (non-standard method)
    if (typeof (input as any).setRangeText === "function") {
      (input as any).setRangeText(text);
    } else {
      if (canManipulateViaTextNodes(input)) {
        const textNode = document.createTextNode(text);
        let node = input.firstChild;

        // If textarea is empty, just insert the text
        if (!node) {
          input.appendChild(textNode);
        } else {
          // Otherwise we need to find a nodes for start and end
          let offset = 0;
          let startNode = null;
          let endNode = null;

          // To make a change we just need a Range, not a Selection
          const range = document.createRange();

          while (node && (startNode === null || endNode === null)) {
            const nodeLength = node.nodeValue.length;

            // if start of the selection falls into current node
            if (start >= offset && start <= offset + nodeLength) {
              range.setStart((startNode = node), start - offset);
            }

            // if end of the selection falls into current node
            if (end >= offset && end <= offset + nodeLength) {
              range.setEnd((endNode = node), end - offset);
            }

            offset += nodeLength;
            node = node.nextSibling;
          }

          // If there is some text selected, remove it as we should replace it
          if (start !== end) {
            range.deleteContents();
          }

          // Finally insert a new node. The browser will automatically
          // split start and end nodes into two if necessary
          range.insertNode(textNode);
        }
      } else {
        // For the text input the only way is to replace the whole value :(
        const value = input.value;
        input.value = value.slice(0, start) + text + value.slice(end);
      }
    }

    // Correct the cursor position to be at the end of the insertion
    input.setSelectionRange(start + text.length, start + text.length);

    // Notify any possible listeners of the change
    const e = document.createEvent("UIEvent");
    e.initEvent("input", true, false);
    input.dispatchEvent(e);
  }
}

function canManipulateViaTextNodes(input: HTMLTextAreaElement | HTMLInputElement) {
  if (input.nodeName !== "TEXTAREA") {
    return false;
  }
  let browserSupportsTextareaTextNodes;
  if (typeof browserSupportsTextareaTextNodes === "undefined") {
    const textarea = document.createElement("textarea");
    textarea.value = "1";
    browserSupportsTextareaTextNodes = !!textarea.firstChild;
  }
  return browserSupportsTextareaTextNodes;
}

-1

Mengubahnya menjadi getElementById (myField)

 function insertAtCursor(myField, myValue) {
    //IE support
    if (document.selection) {
        document.getElementById(myField).focus();
        sel = document.selection.createRange();
        sel.text = myValue;
    }
    //MOZILLA and others
    else if (document.getElementById(myField).selectionStart || document.getElementById(myField).selectionStart == '0') {
        var startPos = document.getElementById(myField).selectionStart;
        var endPos = document.getElementById(myField).selectionEnd;
        document.getElementById(myField).value = document.getElementById(myField).value.substring(0, startPos)
            + myValue
            + document.getElementById(myField).value.substring(endPos, document.getElementById(myField).value.length);
    } else {
        document.getElementById(myField).value += myValue;
    }
}

3
Itu akan menghantam DOM lebih dari yang Anda butuhkan .. menyimpan myfieldsebagai lokal jauh lebih baik untuk kinerja
TMan

2
Wow, benar-benar terlalu banyak pengulangan document.getElementById(myField)! Lakukan sekali di atas dan gunakan nama variabel. Berapa kali berturut-turut Anda berniat mencari elemen yang sama secara berulang?
doug65536
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.