Вставить текст под курсором в редактируемый контент div

У меня есть contenteditable div, где мне нужно вставить текст в позицию курсора,

Это легко сделать в IE с помощью document.selection.createRange().text = "banana"

Есть ли аналогичный способ реализовать это в Firefox / Chrome?

(Я знаю, что решение существует здесь, но его нельзя использовать в contenteditable div, и он выглядит неуклюже)

Спасибо!


person user314362    schedule 27.05.2010    source источник
comment
Если вы хотите вставить html в курсор, см. stackoverflow.com/questions/6690752/   -  person Kes115    schedule 17.08.2016


Ответы (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 в переменной, а затем передать эту переменную в 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();
        }
    }
}
person Tim Down    schedule 27.05.2010
comment
Спасибо за помощь, я использую это как часть онлайн-редактора кода, в котором всякий раз, когда пользователь вводит. после имени объекта появляется контекстное меню со списком его методов (intellisense / завершение кода). И когда пользователь щелкает имя метода, текст должен быть вставлен после точки в области кода div. Но пока имя метода вставляется в контекстное меню, а не в область кода. - person user314362; 28.05.2010
comment
OK. В этом случае я бы предложил сохранить копию Range / TextRange, представляющего выделение в точке, в которой вы собираетесь отобразить контекстное меню, а затем восстановить выделение из этого после скрытия контекстного меню, но до вставки текста. - person Tim Down; 28.05.2010
comment
@Tim, есть ли встроенный Rangy способ вместо insertTextAtCursor ()? Большое спасибо. - person Michael Low; 17.10.2011
comment
@mikel: Не совсем: вы бы просто использовали урезанную версию первой ветки. function insertTextAtCursor(text) { var range, sel = rangy.getSelection(); if (sel.rangeCount) { range = sel.getRangeAt(0); range.insertNode( document.createTextNode(text) ); } } - person Tim Down; 17.10.2011
comment
Однако это работает (по крайней мере, в IE, единственное место, где я это тестировал), между каждой вставкой есть огромная задержка (~ 3 секунды). Поэтому, если я настрою вставлять 'text' при нажатии кнопки, я могу нажимать кнопку несколько раз, но срабатывает только каждые ~ 3 секунды. Если я использую только код IE, он работает нормально, хотя не работает со вставкой '\t' (только пробел, а не табуляция). - person zeel; 13.02.2012
comment
@zeel: Это не должно быть так медленно. Есть ли пример страницы, которую я могу увидеть? - person Tim Down; 14.02.2012
comment
jsfiddle.net/zeel/ww3Rk: вставки клавиш вкладки '\t' и вставки клавиш '\n'. Кнопка вставки вставляет 'TEXT'. Проблема присутствует в IE9. Отсутствует в Chrome. Также: как сделать так, чтобы он поместил курсор после вставки? Это делается в IE, но в Chrome табуляция / новая строка / и т. Д. Помещается после курсора, что затрудняет использование. - person zeel; 14.02.2012
comment
@zeel: Я обновил вашу скрипку, чтобы переместить курсор в позицию сразу после вставленного текста: jsfiddle.net / ww3Rk / 1. В IE 9 вроде все нормально. - person Tim Down; 15.02.2012
comment
@TimDown, я пробовал, но он не работает с моим редактором. Дополнительные сведения http://stackoverflow.com/questions/16881333/wysiwyg-editor-place-html-content-in-current-position - person Billa; 02.06.2013
comment
если выделить текст вне редактора, этот метод вставит текст туда. Это не ожидал - person Fuxian; 13.01.2016
comment
@Fuxian: Я ожидаю этого, но я привык к API выбора, который одинаков как для редактируемого, так и для нередактируемого текста. Если вас это беспокоит, вы можете проверить, доступен ли элемент, содержащий выделение, для редактирования, прежде чем вставлять текст. Я могу предоставить для этого код, если вам нужно. - person Tim Down; 13.01.2016

  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");
        };
    }
    
person Martin Wantke    schedule 22.09.2017
comment
Это решение имеет лучшее поведение, чем принятый ответ, +1. - person goblin GONE; 09.04.2020
comment
1+ для самого простого ответа на вставку / замену sth. пока пользователь печатает. Если я прочитал документ по адресу developer.mozilla.org/en- US / docs / Web / API / Selection / правильно, можно было бы использовать selection.collapseToEnd () без цикла for (). - person Munneson; 28.08.2020
comment
@Munneson: ты пробовал? Это только в том случае, если что-то в данный момент выбрано. Вставленный узел не выбран, он отображается справа от выделения. - person Han Seoul-Oh; 25.05.2021

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')
person alex_1948511    schedule 18.04.2019
comment
Из MDN относительно execCommand: эта функция устарела. Хотя он все еще может работать в некоторых браузерах, его использование не рекомендуется, так как оно может быть удалено в любое время. Старайтесь не использовать его. - person Jens; 04.04.2020
comment
Я действительно надеюсь, что, сделав execCommand устаревшим, браузеры подумали бы о предложении элегантного API для взаимодействия с редактируемым контентом. Этого не произошло. - person Frenchcooc; 25.11.2020

Я использовал следующий код для вставки значков в сообщение чата

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

введите здесь описание изображения

person Sergey Kharchishin    schedule 19.04.2020

просто более простой метод с jquery:

скопируйте все содержимое div

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

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

//element with new html would be

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

просто!

person Alireza Mn    schedule 28.06.2017
comment
Не решает первоначальный вопрос, добавляет текст после содержимого html. - person Tobi; 09.08.2017