代码之家  ›  专栏  ›  技术社区  ›  NeilC

在ContentEditable元素上拖放

  •  14
  • NeilC  · 技术社区  · 16 年前

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

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

    在可编辑元素的特定位置插入HTML很容易,但是当用户在可编辑区域的某个元素上拖动一个DIV时,如何确定插入符号应该在哪里。为了更好地说明我要解释的内容,请参阅以下场景。

    可编辑区域(处于编辑模式的iframe或其contentEditable属性设置为true的div)已经包含以下文本:

    “亲爱的,请注意……”

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

    “亲爱的用户名,请注意…”

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

    任何帮助都将不胜感激。

    3 回复  |  直到 14 年前
        1
  •  6
  •   NeilC    14 年前

    下面是我解决可编辑元素上自定义拖动元素问题的方法。最大的问题是,当鼠标悬停在可编辑元素上时,无法确定鼠标光标的文本偏移量。我试过用鼠标单击来将插入符号设置到所需位置,但这不起作用。即使是这样,在拖动时也看不到插入符号的位置,只看到结果的放置。

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

    包装之后,应该再次找到所有包装好的文本节点,并用一个类名用另一个跨度包装每个字符,这样可以再次找到它们。

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

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

    使用浏览器的range&selection对象,现在可以使用计算的偏移量将选择设置为适用的文本节点,并在新设置的选择(插入符号位置)处插入所需的HTML,et viola!

    下面是一个使用jquery的片段,它将查找textnode,并将其包装:

    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);
    });
    

    希望这种方法能帮助那些面临类似挑战的人

        2
  •  2
  •   Daniel H    14 年前

    如果我理解你的意思,那么这只是基本的拖放操作。下面的解决方案应该接近火狐的最佳答案。我肯定有不同的功能 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;
    }
    
        3
  •  1
  •   Na7coldwater    16 年前

    目前正在开发一个HTML5 API来实现这一点, 但不幸的是,我不支持。 编辑:显然IE确实支持拖放,但我不太熟悉它的工作原理。尝试 Googling “即拖放”。

    尝试查看这些网站:

    推荐文章