현재 커서 위치에서 텍스트 영역에 텍스트를 삽입하는 방법은 무엇입니까?


125

사용자 커서 위치의 텍스트 영역에 텍스트를 추가하는 간단한 함수를 만들고 싶습니다. 깨끗한 기능이 필요합니다. 기본입니다. 나머지는 알아낼 수 있습니다.



2
이 답변을 살펴 이미 게시 보자 stackoverflow.com/questions/4456545/...
존 Culviner



실행 취소를 지원하는 간단한 모듈을 찾고 있다면 insert-text-textarea를 사용 해보세요 . IE8 + 지원이 필요한 경우 insert-text-at-cursor 패키지를 사용해보십시오 .
fregante

답변:


116
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
"손실 캐럿 위치"수정 : 이전에 다음 줄을 추가하십시오} else { myField.selectionStart = startPos + myValue.length; myField.selectionEnd = startPos + myValue.length;
user340140

10
답변에 대해 Rab에게 감사하고 수정에 대해 @ user340140에 감사드립니다. 다음은 작동하는 예 입니다.
Znarkus

@ user340140, "잃어버린 캐럿 포티 션"수정은 당신이 제안한 라인 바로 앞의 입력에 초점을 맞춘 경우에만 작동합니다. 그것은 크롬 적어도, 비 초점을 맞춘 필드에서 선택을 변경하는 것은 불가능 것으로 보인다 (현재 버전 62.0)
Jette

이 코드에는 사소한 문제 selectionStart가 있습니다. 숫자 값이므로와 비교 해야하며를 사용 0하지 '0'않아야합니다.===
Herohtar

82

이 스 니펫은 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);
});

큰! 1.6에서도 약간의 수정이 필요합니다.
Șerban Ghiță

1
하지만 선택한 텍스트를 바꿀 수 없습니다
Sergey Goliney 2014-06-27

@mparkuk : user340140이 위에서 언급 한 "캐럿 위치 손실"문제가 여전히 발생합니다. (죄송합니다.
고쳐야하는데

4
작동하는 바이올린을 제공해 주셔서 감사합니다. 또한 캐럿 위치를 재설정을 업데이트하고 그것을 jQuery 플러그인했습니다 : jsfiddle.net/70gqn153
freedomn-m를

이것은 작동하지만 커서가 잘못된 위치에 있습니다.
AndroidDev 2019 년

36

적절한 자바 스크립트를 위해

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

아주 좋은 확장! 예상대로 작동합니다. 감사!
Martin Johansson

최고의 솔루션! 감사합니다
Dima Melnik

4
소유하지 않은 개체의 프로토 타입을 확장하는 것은 좋은 생각이 아닙니다. 그냥 일반 함수로 만들면 잘 작동합니다.
fregante

이렇게하면 설정 후 편집 요소의 실행 취소 버퍼가 지워 this.value = ...집니다. 그것을 보존 할 방법이 있습니까?
c00000fd

19

새로운 답변 :

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

그래도 브라우저 지원에 대해 잘 모르겠습니다.

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>

이전 답변 :

Erik Pukinskis의 대답에 대한 순수한 JS 수정 :

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>

Chrome 47, 81 및 Firefox 76에서 테스트되었습니다.

자동 완성 또는 유사한 효과를 위해 동일한 필드에 입력하는 동안 현재 선택한 텍스트의 값을 변경 document.activeElement하려면 첫 번째 매개 변수로 전달 합니다.

이 작업을 수행하는 가장 우아한 방법은 아니지만 매우 간단합니다.

사용 예 :

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

>>로 줄을 닫지 않았습니다. <<
Phoenix

4
@Phoenix 세미콜론은 Javascript에서 선택 사항입니다. 그들 없이도 작동합니다. 하지만 원한다면 세미콜론으로 편집 할 수 있습니다. 별거 아니야.
Jayant Bhawal

3
JSFiddle에서 데모를 만들었습니다. Version 54.0.2813.0 canary (64-bit)기본적으로 Chrome Canary 54.0.2813.0 인을 사용하여 작동합니다 . 마지막으로 ID로 텍스트 상자에 삽입 하려면 함수 document.getElementById('insertyourIDhere')에서 대신 사용 el하십시오.
haykam

내 대답의 어떤 부분이 "순수한"JS가 아닌가? 거기에 C ++를 잊었습니까?
에릭 아이그너

2
안녕하세요 @ErikAigner! 내 잘못은,이 질문에 Erik이 두 사람의 답을 가지고 있다는 것을 몰랐습니다. 내 말은 Erik Pukinskis. 더 잘 반영하기 위해 답변을 업데이트하겠습니다.
Jayant Bhawal

15

파이어 폭스, 크롬, 오페라, 사파리, 엣지에서 작동하지만 아마도 오래된 IE 브라우저에서는 작동하지 않을 간단한 솔루션입니다.

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

setRangeText기능을 사용하면 현재 선택을 제공된 텍스트로 대체하거나 선택하지 않은 경우 커서 위치에 텍스트를 삽입 할 수 있습니다. 내가 아는 한 파이어 폭스에서만 지원됩니다.

다른 브라우저의 경우 현재 포커스가있는 html 요소에만 영향을 미치고 다음과 동일한 동작을하는 "insertText"명령이 있습니다. setRangeText

이것에서 부분적으로 영감을 얻음 기사에서


이것은 거의 올바른 방법입니다. 링크 한 기사는 전체 솔루션을 패키지로 제공합니다. insert-text-at-cursor . 그러나 나는 insert-text-textarea를execCommand 지원 undo하고 만들었 기 때문에 선호 합니다 . 아니 IE 지원하지만 작은
fregante

1
불행히도 execCommandMDN에서 쓸모없는 것으로 간주됩니다. developer.mozilla.org/en-US/docs/Web/API/Document/execCommand 이유를 모르겠습니다. 정말 유용한 것 같습니다!
Richard

1
예, execCommand는 다른 브라우저에 사용되며, firefox의 경우 setRangeText 함수가 대신 사용됩니다.
Ramast

Ramast, 그것은 당신의 코드가하는 일이 아닙니다. (대부분) 정의하는 모든 브라우저에 대해 execCommand가 아닌 setRangeText를 사용합니다. 설명하는 동작에 대해 먼저 document.execCommand를 호출 한 다음 반환 값을 확인해야합니다. 거짓이면 target.setRangeText를 사용하십시오.
Jools

@Jools setRangeText가 지원되는 경우 execCommand 대신 사용하지 않는 이유는 무엇입니까? execCommand를 먼저 시도해야하는 이유는 무엇입니까?
Ramast

10

Rab의 답변은 훌륭하게 작동하지만 Microsoft Edge에는 적용되지 않으므로 Edge에도 약간의 적응을 추가했습니다.

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

저는 간단한 자바 스크립트를 좋아하고 보통 jQuery를 가지고 있습니다. 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
})

데모 : 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

텍스트가 삽입 된 후 사용자가 입력을 터치하지 않으면 'input'이벤트가 트리거되지 않으며 value 속성이 변경 사항을 반영하지 않습니다. 따라서 프로그래밍 방식으로 텍스트를 삽입 한 후 입력 이벤트를 트리거하는 것이 중요합니다. 필드에 초점을 맞추는 것만으로는 충분하지 않습니다.

다음은 끝에 입력 트리거가있는 Snorvarg의 답변 사본입니다 .

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

triggerEvent 함수에 대한 plainjs.com에 대한 크레딧

w3schools.com 의 oninput 이벤트에 대한 추가 정보

채팅 용 이모티콘 선택기를 만드는 동안 이것을 발견했습니다. 사용자가 이모 지 몇 개를 선택하고 "보내기"버튼을 누르면 사용자가 입력 필드를 터치하지 않습니다. 값 속성을 확인할 때 삽입 된 이모 지 유니 코드가 입력 필드에 표시 되더라도 항상 비어있었습니다. 사용자가 필드를 터치하지 않으면 '입력'이벤트가 발생하지 않았으며 해결책은 이와 같이 트리거하는 것이 었습니다. 이걸 알아내는 데 꽤 오랜 시간이 걸렸습니다. 누군가 시간을 절약 할 수 있기를 바랍니다.


0

자신의 참조를 위해 수정 된 기능을 게시합니다. 이 예제는 <select>개체 에서 선택한 항목을 삽입 하고 태그 사이에 캐럿을 넣습니다.

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

이것이 질문에 답할 수는 있지만 답의 필수 부분과 OP 코드의 문제점을 설명하는 것이 좋습니다.
pirho

0

아래 코드는 Dmitriy Kubyshkin의 https://github.com/grassator/insert-text-at-cursor 패키지의 TypeScript 적응입니다 .


/**
 * 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

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
그것은 당신이 .. 저장하는 데 필요한 것보다 더 많은 DOM 방식을 칠려고 myfield성능을 위해 더 나은 로컬로한다
TMan

2
와우, 정말 너무 많이 반복 document.getElementById(myField)! 상단에서 한 번 수행하고 변수 이름을 사용하십시오. 동일한 요소를 중복해서 조회하려고 한 행에서 몇 번입니까?
doug65536
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.