在内容可编辑的 div 中的光标处插入文本

我有一个可满足的 div,需要在插入符号位置插入文本,

这可以很容易地做到 IE 的 document.selection.createRange().text = "banana"

在 Firefox/Chrome 中有类似的实现方法吗?

(我知道有一个解决方案存在 给你,但是它不能在可满足的 div 中使用,而且看起来很笨拙)

谢谢!

76127 次浏览

下面的函数将在插入符号位置插入文本并删除现有的选定内容。它适用于所有主流的桌面浏览器:

function insertTextAtCaret(text) {
var sel, range;
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
range = sel.getRangeAt(0);
range.deleteContents();
range.insertNode( document.createTextNode(text) );
}
} else if (document.selection && document.selection.createRange) {
document.selection.createRange().text = text;
}
}

更新

基于注释,下面是一些保存和恢复选择内容的代码。在显示上下文菜单之前,应该将 saveSelection的返回值存储在一个变量中,然后将该变量传递给 restoreSelection,以便在隐藏上下文菜单之后和插入文本之前恢复所选内容。

function saveSelection() {
if (window.getSelection) {
sel = window.getSelection();
if (sel.getRangeAt && sel.rangeCount) {
return sel.getRangeAt(0);
}
} else if (document.selection && document.selection.createRange) {
return document.selection.createRange();
}
return null;
}


function restoreSelection(range) {
if (range) {
if (window.getSelection) {
sel = window.getSelection();
sel.removeAllRanges();
sel.addRange(range);
} else if (document.selection && range.select) {
range.select();
}
}
}

使用 jquery 只是一个更简单的方法:

复制 div 的全部内容

var oldhtml=$('#elementID').html();

var tobejoined='<span>hii</span>';

//element with new html would be

$('#elementID').html(oldhtml+tobejoined);

简单!

  1. 使用 window.getSelection()获取选择对象。
  2. 使用 Selection.getRangeAt(0).insertNode()添加文本节点。
  3. 如果需要,使用 Selection.modify()将光标位置移到添加的文本后面。(没有标准化,但 Firefox、 Chrome 和 Safari 都支持这个功能)

    function insertTextAtCursor(text)
    {
    let selection = window.getSelection();
    let range = selection.getRangeAt(0);
    range.deleteContents();
    let node = document.createTextNode(text);
    range.insertNode(node);
    
    
    for(let position = 0; position != text.length; position++)
    {
    selection.modify("move", "right", "character");
    };
    }
    

UPD: 因为 ~ 2020解决方案是 一个 href = “ https://developer.mozilla.org/en-US/docs/Web/API/document/ExecCommand”rel = “ norefrer”> 过时的 (尽管它可以 工作)

// <div contenteditable id="myeditable">
// const editable = document.getElementById('myeditable')
// editable.focus()
// document.execCommand('insertHTML', false, '<b>B</b>anana')
document.execCommand('insertText', false, 'banana')

我已经使用下面的代码在聊天 msg 中插入图标

<div class="chat-msg-text" id="chat_message_text" contenteditable="true"></div>


<script>
var lastCaretPos = 0;
var parentNode;
var range;
var selection;


$(function(){
$('#chat_message_text').focus();


$('#chat_message_text').on('keyup mouseup',function (e){
selection = window.getSelection();
range = selection.getRangeAt(0);
parentNode = range.commonAncestorContainer.parentNode;
});
})


function insertTextAtCursor(text) {


if($(parentNode).parents().is('#chat_message_text') || $(parentNode).is('#chat_message_text') )
{
var span = document.createElement('span');
span.innerHTML=text;


range.deleteContents();
range.insertNode(span);
//cursor at the last with this
range.collapse(false);
selection.removeAllRanges();
selection.addRange(range);


}
else
{
msg_text = $("#chat_message_text").html()
$("#chat_message_text").html(text+msg_text).focus()
}
}


</script>

enter image description here

粘贴纯文本可以使用以下代码进行处理。

const editorEle = document.getElementById('editor');


// Handle the `paste` event
editorEle.addEventListener('paste', function (e) {
// Prevent the default action
e.preventDefault();


// Get the copied text from the clipboard
const text = e.clipboardData
? (e.originalEvent || e).clipboardData.getData('text/plain')
: // For IE
window.clipboardData
? window.clipboardData.getData('Text')
: '';


if (document.queryCommandSupported('insertText')) {
document.execCommand('insertText', false, text);
} else {
// Insert text at the current position of caret
const range = document.getSelection().getRangeAt(0);
range.deleteContents();


const textNode = document.createTextNode(text);
range.insertNode(textNode);
range.selectNodeContents(textNode);
range.collapse(false);


const selection = window.getSelection();
selection.removeAllRanges();
selection.addRange(range);
}
});

如果您使用的是富编辑器(如 DraftJs) ,但无法访问它们的 API (如从扩展进行修改) ,那么我找到了以下解决方案:

  • 发送 beforeinput事件,这是推荐的方法,并且大多数编辑器都支持
target.dispatchEvent(new InputEvent("beforeinput", {
inputType: "insertText",
data: text,
bubbles: true,
cancelable: true
}))
  • 发送 paste事件
const data = new DataTransfer();
data.setData(
'text/plain',
text
);
target.dispatchEvent(new ClipboardEvent("paste", {
dataType: "text/plain",
data: text,
bubbles: true,
clipboardData: data,
cancelable: true
}));

最后一个使用了两种不同的方法:


如果要替换所有现有文本,必须首先选择它

function selectTargetText(target) {
const selection = window.getSelection();
const range = document.createRange();
range.selectNodeContents(target);
selection.removeAllRanges();
selection.addRange(range);
}


selectTargetText(target)


// wait for selection before dispatching the `beforeinput` event
document.addEventListener("selectionchange",()=>{
target.dispatchEvent(new InputEvent("beforeinput", {
inputType: "insertText",
data: text,
bubbles: true,
cancelable: true
}))
},{once: true})