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


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.