在 contentEditable 元素中插入 HTML 元素

Posted

技术标签:

【中文标题】在 contentEditable 元素中插入 HTML 元素【英文标题】:Insert an HTML element in a contentEditable element 【发布时间】:2011-06-16 23:00:32 【问题描述】:

我有一个 contentEditable div,我想在其中插入 html 标记(一个简单的 span 元素)。

是否有跨浏览器解决方案允许我将这些标签插入到我的 div 选择或光标位置。如果在页面上选择了其他内容(不在 div 中),我想将标签附加到 div 的末尾。

谢谢

【问题讨论】:

你使用 JS 库吗? 【参考方案1】:

这是一个快速启动

// get the selection range (or cursor     position)
var range = window.getSelection().getRangeAt(0); 
// create a span
var newElement = document.createElement('span');
newElement.id = 'myId';
newElement.innerHTML = 'Hello World!';

// if the range is in #myDiv ;)
if(range.startContainer.parentNode.id==='myDiv') 
   // delete whatever is on the range
   range.deleteContents();
   // place your span
   range.insertNode(newElement);

我没有 IE,但在 firefox、chrome 和 safari 上运行良好。也许您只想在 contentEditable div 上进行选择时才继续使用 range.startContainer。

编辑:根据quirksmode range intro,您必须将 window.getSelection() 部分更改为与 IE 兼容。

var userSelection;
if (window.getSelection) 
    userSelection = window.getSelection();

else if (document.selection)  // should come last; Opera!
    userSelection = document.selection.createRange();

【讨论】:

感谢您的快速回复。它没有解决我的问题,还有一个缺失的部分:即使用户试图在其他地方选择,我也只想在 div 中插入节点......如何检查用户是否在 div 内选择?跨度> range.startContainer (正如我在答案中所写)返回范围开始的 DOM 元素。您可以在插入新内容之前检查该元素是否是您的 div。 您还没有真正解决 IE 部分,并且检查范围是否包含在 <div> 中很弱:如果范围开始于嵌套元素或如果范围不在文本节点内开始,或者范围在 <div> 之外结束。 是的,这是一个启动。你的回答很棒【参考方案2】:

以下将在所有主流浏览器(包括 IE 6)中执行此操作。它还将处理选择结束在您的<div> 之外的情况,以及选择包含在<div> 内的子(或更深层嵌套)元素中的情况。

2019 附录insertNodeOverSelection 的第二个分支仅适用于 IE

function isOrContainsNode(ancestor, descendant) 
    var node = descendant;
    while (node) 
        if (node === ancestor) return true;
        node = node.parentNode;
    
    return false;


function insertNodeOverSelection(node, containerNode) 
    var sel, range, html;
    if (window.getSelection) 
        sel = window.getSelection();
        if (sel.getRangeAt && sel.rangeCount) 
            range = sel.getRangeAt(0);
            if (isOrContainsNode(containerNode, range.commonAncestorContainer)) 
                range.deleteContents();
                range.insertNode(node);
             else 
                containerNode.appendChild(node);
            
        
     else if (document.selection && document.selection.createRange) 
        range = document.selection.createRange();
        if (isOrContainsNode(containerNode, range.parentElement())) 
            html = (node.nodeType == 3) ? node.data : node.outerHTML;
            range.pasteHTML(html);
         else 
            containerNode.appendChild(node);
        
    
<input type="button" onmousedown="insertNodeOverSelection(document.createTextNode('[NODE]'), document.getElementById('test'));" value="insert">

<div contenteditable="true">
    <div id="test" style="background-color: lightgoldenrodyellow">
        This is the editable element where the insertion will happen. Select something or place the cursor in here, then hit the button above
    </div>
    <div>
        No insertion will happen here
    </div>
</div>

【讨论】:

嘿,蒂姆,距离这个答案已经 8 年了,我们还需要“insertNodeOverSelection”函数的最后一部分来支持旧版浏览器/IE 吗? ...“否则如果”之后? @Norman:没有。IE 从版本 9 开始就有必要的 Range 和 Selection API。

以上是关于在 contentEditable 元素中插入 HTML 元素的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 html 子元素在 contenteditable div 中获取插入符号位置?

更改 contenteditable 元素的 innerHTML 后,将插入符号放回原来的位置

将插入符号位置设置为零在 chrome 中的 contenteditable 元素的节点内

如何使用 contentEditable 获取 iframe 中当前插入符号位置的像素偏移量

在 contenteditable div 中的特定位置设置插入符号位置

获取内容可编辑的插入符号位置