在contentEditable元素上拖放n-Drop

时间:2010-06-09 14:09:23

标签: javascript drag-and-drop contenteditable

互联网上有许多WYSIWYG编辑器,但我还没有找到一种实现某种形式的拖放实现的编辑器。

创建一个自己的编辑器很容易,但我希望用户能够从可编辑区域外拖动元素(即标记),并将它们放在可编辑区域内选择的位置。

在可编辑元素的特定位置注入html很容易,但是当用户在可编辑区域中的某个元素上拖动DIV时,如何确定插入符应该位于何处。为了更好地说明我要解释的内容,请参阅以下方案。

可编辑区域(编辑模式下的IFRAME或其contentEditable属性设置为true的DIV)已包含以下文本:

“亲爱的,请注意......”

用户现在从可编辑区域上的元素列表中拖动表示某个标记的元素,将光标移动到文本上,直到插入符号出现在文本中的逗号(,)之前,如上所示。当用户在该位置释放鼠标按钮时,将注入HTML,这可能导致如下所示:

“亲爱的{UserFirstName},请注意......”。

我不知道是否有人做过类似的事情,或者至少知道如何使用JavaScript来做这件事。

非常感谢任何帮助。

3 个答案:

答案 0 :(得分:6)

以下是解决可编辑元素上自定义拖动元素问题的方法。最大的问题是当鼠标悬停在可编辑元素上时,无法确定鼠标光标的文本偏移量。我曾尝试伪造鼠标单击以将插入符号设置在所需位置,但这不起作用。即使它确实如此,人们也不会在拖动时直观地看到插入符号的位置,而只会看到产生的掉落。

由于可以将鼠标悬停事件绑定到元素而不是文本节点,因此可以将可编辑元素设置为暂时不可编辑。查找所有元素并将每个文本节点包装在一个范围中,以便不破坏文本流。应为每个范围指定一个类名,以便我们再次找到它们。

在包装之后,应该再次找到所有包装的文本节点,并用另一个带有可以再次找到它们的类名的span来包装每个字符。

使用事件委托可以向主可编辑元素添加一个事件,该元素将一个样式应用于将显示插入符号的每个字符跨度,一个闪烁的GIF图像作为背景。

同样,使用事件委托,应该为每个字符添加鼠标向上事件(drop事件)的事件。现在可以使用其父级(包装文本节点)中的字符跨度位置(偏移量)来确定偏移量。现在可以撤消所有包装,保持对计算的偏移的引用,同时撤消包装,保留对适用的文本节点的引用。

使用范围&浏览器的选择对象,现在可以使用计算的偏移量将选择设置为适用的文本节点,并在新设置的选择(插入位置),中提琴上注入所需的HTML!

下面是一个使用jQuery的代码片段,它将找到文本节点,包装它们:

editElement.find("*:not(.text-node)").contents().filter(function(){ 
    return this.nodeType != 1;
}).wrap("<span class=\"text-node\"/>");

要查找每个文本节点并包装每个字符,请使用:

editElement.find(".text-node").each(function()
{
    var textnode = $(this), text = textnode.text(), result = [];

    for (var i = 0; i < text.length; i++) result.push(text.substr(i, 1));

    textnode.html("<span class=\"char\">" 
        + result.join("</span><span class=\"char\">") + "</span>");
});

撤消包装:

editElement.find(".text-node").each(function()
{
    this.parentNode.replaceChild(document.createTextNode($(this).text()), this);
});

希望这种方法可以帮助那些有类似挑战的人

答案 1 :(得分:2)

如果我明白你在说什么,那么这只是基本的拖放。下面的解决方案应该接近FIREFOX的最佳答案。我确信IE有不同的功能。转到http://www.html5rocks.com/en/tutorials/dnd/basics/获取更多帮助。

设置要拖动的对象的“draggable”属性,并将对象的“ondragstart”方法设置为“dragStartHandler”或任何函数调用。

// You can set this to 'text/plain' if you don't want to insert HTML content
var internalDNDType = 'text/html';

function dragStartHandler(event) {
  // This is whatever html data you want to insert.
  var textContent = "<b>"+userFirstName+"</b>";

  event.dataTransfer.setData(internalDNDType, textContent);
  event.dataTransfer.effectAllowed = 'copy';
}

function dragEnterHandler(event)
{
  event.preventDefault();
  return false;
}

function dragOverHandler(event)
{
  event.preventDefault();
  return false;
}

function dropHandler(event) {
  event.preventDefault();
  event.stopPropogation();
  return false;
}

答案 2 :(得分:1)

目前正在开发一个HTML5 API来执行此操作,但不幸的是IE不支持它。编辑:显然IE实际上支持拖放,但我不是很熟悉如何有用。尝试Googling“IE拖放”。

尝试查看这些网站: