Javascript 如何在当前光标位置的文本区域中插入文本?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/11076975/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-24 04:20:13  来源:igfitidea点击:

How to insert text into the textarea at the current cursor position?

javascripttextarea

提问by JoshMWilliams

I would like to create a simple function that adds text into a text area at the user's cursor position. It needs to be a clean function. Just the basics. I can figure out the rest.

我想创建一个简单的函数,将文本添加到用户光标位置的文本区域中。它需要是一个干净的功能。只是基础知识。我可以弄清楚其余的。

回答by Raab

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

回答by Adriano Alves

This snippet could help you with it in a few lines of jQuery 1.9+: http://jsfiddle.net/4MBUG/2/

此代码段可以在几行 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);
});

回答by Erik Aigner

For the sake of proper Javascript

为了正确的 Javascript

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

回答by Jayant Bhawal

New answer:

新答案:

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

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

I'm not sure about the browser support for this though.

不过,我不确定浏览器对此的支持。

Tested in Chrome 81.

在 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>

Old answer:

旧答案:

A pure JS modification of Erik Pukinskis' answer:

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>

Tested in Chrome 47, 81, and Firefox 76.

在 Chrome 47、81 和 Firefox 76 中测试。

If you want to change the value of the currently selected text while you're typing in the same field (for an autocomplete or similar effect), pass document.activeElementas the first parameter.

如果要在同一字段中键入时更改当前选定文本的值(用于自动完成或类似效果),请document.activeElement作为第一个参数传递。

It's not the most elegant way to do this, but it's pretty simple.

这不是最优雅的方法,但它非常简单。

Example usages:

示例用法:

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

回答by Ramast

A simple solution that work on firefox, chrome, opera, safari and edge but probably won't work on old IE browsers.

一个简单的解决方案,适用于 firefox、chrome、opera、safari 和 edge,但可能不适用于旧的 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);
  }
}

setRangeTextfunction allow you to replace current selection with the provided text or if no selection then insert the text at cursor position. It's only supported by firefox as far as I know.

setRangeText功能允许您用提供的文本替换当前选择,或者如果没有选择则在光标位置插入文本。据我所知,它仅受 Firefox 支持。

For other browsers there is "insertText" command which only affect the html element currently focused and has same behavior as setRangeText

对于其他浏览器,有“insertText”命令,它只影响当前聚焦的 html 元素,并且具有相同的行为 setRangeText

Inspired partially by this article

部分灵感来自这篇文章

回答by Snorvarg

Rab's answer works great, but not for Microsoft Edge, so I added a small adaptation for Edge as well:

Rab 的回答很有效,但不适用于 Microsoft Edge,因此我也为 Edge 添加了一个小改动:

https://jsfiddle.net/et9borp4/

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

回答by Erik Pukinskis

I like simple javascript, and I usually have jQuery around. Here's what I came up with, based off mparkuk's:

我喜欢简单的 javascript,我通常有 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
})

Here's a demo: http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101

这是一个演示:http: //codepen.io/erikpukinskis/pen/EjaaMY?editors= 101

回答by u5602117


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>

回答by Jette

If the user does not touch the input after text is inserted, the 'input' event is never triggered, and the value attribute will not reflect the change. Therefore it is important to trigger the input event after programmatically inserting text. Focusing the field is not enough.

如果用户在插入文本后没有触摸输入,则永远不会触发 'input' 事件,并且 value 属性不会反映更改。因此,在以编程方式插入文本后触发输入事件非常重要。专注于该领域是不够的。

The following is a copy of Snorvarg's answerwith an input trigger at the end:

以下是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);
  }
}

Credit to plainjs.comfor the triggerEvent function

感谢plainjs.com为triggerEvent功能

More about the oninput event at w3schools.com

有关w3schools.com 上的 oninput 事件的更多信息

I discovered this while creating an emoji-picker for a chat. If the user just select a few emojis and hit the "send" button, the input field is never touched by the user. When checking the value attribute it was always empty, even though the inserted emoji unicodes was visible in the input field. Turns out that if the user does not touch the field the 'input' event never fired and the solution was to trigger it like this. It took quite a while to figure this one out... hope it will save someone some time.

我在为聊天创建表情符号选择器时发现了这一点。如果用户只选择几个表情符号并点击“发送”按钮,则用户永远不会触摸输入字段。检查 value 属性时,它始终为空,即使插入的 emoji unicodes 在输入字段中可见。事实证明,如果用户不触摸该字段,则 'input' 事件永远不会触发,解决方案是像这样触发它。花了很长时间才弄明白这个……希望它可以节省一些时间。

回答by André Pena

The code below is a TypeScript adaptation of the package https://github.com/grassator/insert-text-at-cursorby Dmitriy Kubyshkin.

下面的代码是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;
}