我想创建一个简单的函数,将文本添加到用户光标位置的文本区域中。它需要是一个简洁的函数,只包含基本功能。我可以自己处理其余部分。
我想创建一个简单的函数,将文本添加到用户光标位置的文本区域中。它需要是一个简洁的函数,只包含基本功能。我可以自己处理其余部分。
使用输入元素的selectionStart
/selectionEnd
属性(对于<textarea>
也适用)
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;
}
}
} else {
之前添加以下代码行:myField.selectionStart = startPos + myValue.length;
myField.selectionEnd = startPos + myValue.length;
这将使得文本框中的插入符号回到正确的位置。请注意,此操作不会改变原始代码的含义,只是添加了一些代码以解决问题。 - user340140selectionStart
是一个数值,因此应该与 0
进行比较,而不是 '0'
,并且可能应该使用 ===
。 - Herohtar这段代码可以用几行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);
});
https://developer.mozilla.org/zh-CN/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'));
document.getElementById('insertyourIDhere')
代替el
。 - bb216b3acfd8f72cbc8f899d4d6963Erik Pukinskis
。我会更新答案以更好地反映这一点。 - Jayant BhawalHTMLTextAreaElement.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;
}
};
this.value = ...
后,这将清除编辑元素的撤消缓冲区。有没有办法保留它? - c00000fdA.prototype.fn = X
是拥有“类”/继承的唯一方法。仅仅因为你可以扩展你的对象,这并不意味着你应该扩展_原生_对象。想象一下十年前你实现了 Array.map()
,然后 Array.map()
成为了一个原生 API,但与你的不兼容。现在有人打开你的代码库,并看到 [].map()
并假设它是原生 API。问题来了,错误来了。 - fregante这是一个简单的解决方案,适用于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);
}
setRangeText
函数允许您用提供的文本替换当前选择内容,或者如果没有选择,则将文本插入光标位置。据我所知,目前仅受火狐浏览器支持。
对于其他浏览器,有“insertText”命令,它仅影响当前聚焦的html元素,并具有与setRangeText
相同的行为。
部分灵感来自于这篇文章
execCommand
,因为它支持undo
并且制作了insert-text-textarea。虽然不支持IE但更小。 - freganteexecCommand
被MDN视为已过时:https://developer.mozilla.org/en-US/docs/Web/API/Document/execCommand
我不知道为什么,它似乎非常有用! - RichardexecCommand
,因为正如fregante所说,它支持“撤消”。如果你调用setRangeText
,类似于设置.value
,它会清除撤消/重做堆栈,例如Ctrl+Z和右键单击,撤消将变为不可用。 - Jools我喜欢简单的 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
})
这里是演示:http://codepen.io/erikpukinskis/pen/EjaaMY?editors=101
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;
}
}
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>
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);
}
}
感谢plainjs.com提供的triggerEvent函数
更多关于oninput事件的信息请参考w3schools.com
我在为一个聊天应用程序创建一个表情选择器时发现了这个问题。如果用户只选择了一些表情符号然后点击“发送”按钮,输入框将从未被用户触摸过。当检查value属性时,它始终为空,即使插入的表情符号unicode在输入框中可见。原来,如果用户不触摸输入框,则“input”事件永远不会触发,解决方法是像这样触发它。花了很长时间才弄清楚这个问题... 希望能节省其他人的时间。
/**
* 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;
}