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

IT技术 javascript contenteditable
2021-01-31 05:43:52

我有一个 contenteditable div,我需要在插入符号位置插入文本,

这可以通过以下方式在 IE 中轻松完成 document.selection.createRange().text = "banana"

在 Firefox/Chrome 中是否有类似的实现方式?

(我知道这里有一个解决方案,但它不能用于 contenteditable div,而且看起来很笨拙)

谢谢!

5个回答

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

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在一个变量中,然后将该变量传递restoreSelectionin 以在隐藏上下文菜单后和插入文本之前恢复选择。

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();
        }
    }
}
@Fuxian:我期待它,但我已经习惯了选择 API,这对于可编辑和不可编辑的文本都是相同的。如果您对此感到担心,那么您可以在插入文本之前检查包含所选内容的元素是否可编辑。如果您需要,我可以提供代码。
2021-03-15 05:43:52
@mikel:不是真的:您只需使用第一个分支的缩减版本。 function insertTextAtCursor(text) { var range, sel = rangy.getSelection(); if (sel.rangeCount) { range = sel.getRangeAt(0); range.insertNode( document.createTextNode(text) ); } }
2021-03-29 05:43:52
感谢您的帮助,我将其用作在线代码编辑器的一部分,每当用户键入“。” 在对象名称之后,弹出一个上下文菜单,其中包含其方法列表(智能感知/代码完成)并且当用户单击方法名称时,文本需要粘贴在代码区域 div 中的点之后。但到目前为止,“方法名称”被粘贴在上下文菜单内而不是代码区域内。
2021-03-30 05:43:52
@zeel:我已经更新了你的小提琴,在插入的文本之后立即将光标移动到一个位置:jsfiddle.net/ww3Rk/1在 IE 9 中似乎没问题。
2021-04-06 05:43:52
行。在这种情况下,我建议在您将要显示上下文菜单时存储表示选择的 Range / TextRange 的副本,然后在隐藏上下文菜单后但在插入文本之前从中恢复选择。
2021-04-08 05:43:52
  1. 使用 获取选择对象window.getSelection()
  2. 使用Selection.getRangeAt(0).insertNode()添加textnode。
  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");
        };
    }
    
该解决方案比公认的答案具有更好的行为,+1。
2021-03-26 05:43:52
@Munneson:你试过了吗?仅当当前选择了某些内容时。插入的节点未被选中,它显示在所选内容的右侧。
2021-03-29 05:43:52
1+ 是“在用户键入时插入/替换某物”的最简单答案。如果我正确阅读developer.mozilla.org/en-US/docs/Web/API/Selection/... 上的文档,则可以使用 selection.collapseToEnd() 而不使用 for() 循环。
2021-03-31 05:43:52

UPD:由于 ~2020 解决方案已过时(尽管它还可以工作

// <div contenteditable id="myeditable">
// const editable = document.getElementById('myeditable')
// editable.focus()
// document.execCommand('insertHTML', false, '<b>B</b>anana')
document.execCommand('insertText', false, 'banana')
来自MDN关于execCommand:此功能已过时。尽管它可能在某些浏览器中仍然有效,但不鼓励使用它,因为它可以随时被删除。尽量避免使用它。
2021-03-20 05:43:52
我真的希望在execCommand过时时,浏览器会考虑提出一个优雅的 API 来与可编辑内容进行交互。它没有发生。
2021-04-05 05:43:52

我已经使用下一个代码在聊天消息中插入图标

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

在此处输入图片说明

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

复制div的全部内容

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

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

//element with new html would be

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

简单的!

没有解决最初的问题,它在 html 的内容之后附加了文本。
2021-03-21 05:43:52