Insert text in Javascript contenteditable div

2019-02-03 13:08发布

问题:

I have a problem where I need to insert a text (string, may or may not have html tags) to a div. It has to be a div and not a textarea.

Is there anyway to do that? First of all, I need to get the cursor position, then inserting the text in that position.

It's similar to function insertAdjacentText, but it can only insert before or after a tag, and only works in IE.

Refer to this URL: http://yart.com.au/test/iframe.aspx. Note how you can position the cursor in the div, we need to add text at the cursor location.

回答1:

If all you need to do is insert HTML at the current selection / insertion point, that is doable. Off the top of my head (to get you started):

In IE, use document.selection.createRange().pasteHTML(theNewHTML).

In other browsers, you should be able to use document.execCommand("InsertHTML", ...).

I've used these kinds of techniques only in editable iframes/documents, not divs, but these calls should work if the div is focused, I believe.

As another answer warned, it gets ugly if you want finer-grained control, like inserting text in other places.



回答2:

The Range and Selection Objects

Use the selection and range objects. These contain all kinds of information about the current selection, and where it lies within the node tree.

Fair Warning: It's not entirely impossible to do what you're describing, but if you get very fancy, you'll be in pretty deep water of browser quirks and incompatibilities. You're going to have to do a lot of object detection, checking to make sure you've got consistent values and methods. Incrementally check all of your browsers as you develop. Good luck!



回答3:

Here's a cross-browser example, adapted from this answer to work with iframes.

function pasteHtmlAtCaret(html, selectPastedContent, iframe) {
    var sel, range;
    var win = iframe ? iframe.contentWindow : window;
    var doc = win.document;
    if (win.getSelection) {
        // IE9 and non-IE
        sel = win.getSelection();
        if (sel.getRangeAt && sel.rangeCount) {
            range = sel.getRangeAt(0);
            range.deleteContents();

            // Range.createContextualFragment() would be useful here but is
            // only relatively recently standardized and is not supported in
            // some browsers (IE9, for one)
            var el = doc.createElement("div");
            el.innerHTML = html;
            var frag = doc.createDocumentFragment(), node, lastNode;
            while ( (node = el.firstChild) ) {
                lastNode = frag.appendChild(node);
            }
            var firstNode = frag.firstChild;
            range.insertNode(frag);

            // Preserve the selection
            if (lastNode) {
                range = range.cloneRange();
                range.setStartAfter(lastNode);
                if (selectPastedContent) {
                    range.setStartBefore(firstNode);
                } else {
                    range.collapse(true);
                }
                sel.removeAllRanges();
                sel.addRange(range);
            }
        }
    } else if ( (sel = doc.selection) && sel.type != "Control") {
        // IE < 9
        var originalRange = sel.createRange();
        originalRange.collapse(true);
        sel.createRange().pasteHTML(html);
        if (selectPastedContent) {
            range = sel.createRange();
            range.setEndPoint("StartToStart", originalRange);
            range.select();
        }
    }
}


回答4:

You can also use a round-about method using insertImage. You insert a fake image (or a small one) using the execCommand "insertImage", then you use Javascript to replace the innerHTML to add the text.

For example:

iFrame.focus()
iFrame.document.execCommand("insertImage", "", "fakeimage.jpg")
iFrame.document.body.innerHTML=iFrame.document.body.innerHTML.replace("<img src=\"fakeimage.jpg\">", "MY CUSTOM <b>HTML</b> HERE!")

Whereas iFrame is equal to the id of the intended iFrame. Or, you could use a DIV layer by using document.getElementById("IDofDIVlayer").innerHTML

Be sure to focus before calling the execCommand, otherwise it may not work in IE.

This method works in IE too. Tested.