2013-01-20 53 views
5

我试图使用本机拖放事件重新排列DOM SVG元素。下面的代码似乎在Firefox中工作(有一些奇怪的图像效果),在Chrome中工作的次数有限(2或3次拖放重新排序工作,然后它似乎挂起),并且在IE中不是很好。我最好的猜测是,有关事件的事情我没有正确想到,有些类型的重置。或者用这种方式使用没有dataTransfer的拖动事件是不正确的。我的目标是在没有库的情况下理解这种类型的函数,但要在最基本的层面上更清楚地了解DOM函数,javascript,HTML和CSS。我可能很容易在该清单的任何地方出错。HTML5使用javascript拖放DOM操作

<!DOCTYPE html> 
<html> 
    <head> 
    <title>Drag and Drop Experiments</title> 
    <style>svg { border-width:3px} </style> 
    </head> 
<body> 
    <div id="main"> 
    <svg id="s1" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="blue"></circle> 
    </svg> 
    <svg id="s2" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="red"></circle> 
    </svg> 
    <svg id="s3" draggable="yes" width="100" height="100"> 
     <circle cx="50" cy="50" r="30" fill="yellow"></circle> 
    </svg> 
    </div> 
    <script type="text/javascript"> 
     var dragSourceElement = null; 
     var dragTargetElement = null; 
     function doDragStart(e){ 
      this.style.opacity = "0.4"; 
      this.style.border = "solid"; 
      dragSourceElement = this; 
     } 
     function doDragEnter(e){ 
      if(dragSourceElement != this){ 
      this.style.border = "dashed"; 
      } 
     } 
     function doDragLeave(e){ 
      if(dragSourceElement != this){ 
       this.style.border = ""; 
      } 
     } 
     function doDragOver(e){ 
      if(dragSourceElement != this){ 
       dragTargetElement = this; 
       e.preventDefault();//to allow a drop? 
      } 
     } 
     function doDragEnd(e){ 
      this.style.border = ""; 
      this.style.opacity = "1.0"; 
     } 
     function doDragDrop(e){ 
      if(dragSourceElement != dragTargetElement){ 
      dnd_svg(dragSourceElement,dragTargetElement); 
      } 
      dragSourceElement.style.border = ""; 
      dragTargetElement.style.border = ""; 
      dragSourceElement.style.opacity = ""; 
      dragSourceElement = null; 
      dragTargetElement = null; 
     } 
     //called after a drag and drop 
     //to insert svg element c1 before c2 in the DOM 
     //subtree of the parent of c2, assuming c1 is 
     //dropped onto c2 
     function dnd_svg(c1,c2){ 
     var parent_c2 = c2.parentElement; 
     parent_c2.insertBefore(c1,c2); 
     } 
     function addL(n){ 
      n.addEventListener('dragstart',doDragStart,false); 
      n.addEventListener('dragenter',doDragEnter,false); 
      n.addEventListener('dragleave',doDragLeave,false); 
      n.addEventListener('dragover',doDragOver,false); 
      n.addEventListener('drop',doDragDrop,false); 
     } 
     addL(document.getElementById("s1")); 
     addL(document.getElementById("s2")); 
     addL(document.getElementById("s3")); 
    </script> 
</body> 
</html> 
+0

请注意,IE9中的dnd_svg函数中存在javascript错误。 var parent_c2 = c2.parentElement? c2.parentElement:c2.parentNode;为我解决它。请参阅http://jsfiddle.net/nrNSS/。 – stevebot

回答

0

请参阅this JSFiddle。 FF中SVG的拖放事件存在问题,因此一种解决方案是将包装元素添加到SVG。有了这个,您可以使用dataTransfer方法,然后将该节点追加到放置位置。

<!DOCTYPE HTML> 
<html> 

    <head> 
     <style type="text/css"> 
      #div1,#div2 { 
       width:350px; 
       height:70px; 
       padding:10px; 
       border:1px solid #aaaaaa; 
      } 
     </style> 
     <script> 
      function allowDrop(ev) { 
       ev.preventDefault(); 
      } 

      function drag(ev) { 
       var id = ev.target ? ev.target.id : ev.srcElement.id; 
       if (id === "circle") { 
        id = ev.target.parentNode.parentNode.id; 
       } 
       ev.dataTransfer.setData("Text", id); 
      } 

      function drop(ev) { 
       ev.preventDefault(); 
       var data = ev.dataTransfer.getData("Text"); 
       ev.target.appendChild(document.getElementById(data)); 
      } 
     </script> 
    </head> 

    <body> 

     <div id="div1" ondrop="drop(event)" 
     ondragover="allowDrop(event)"></div> 
      <div id="div2" ondrop="drop(event)" 
     ondragover="allowDrop(event)"></div> 
     <br> 
     <div id="wrapper" draggable="yes" ondragstart="drag(event)" style="width:100px; height:100px;"> 
      <svg id="svg" width="100" height="100" draggable="yes" ondragstart="drag(event)" > 
       <circle id="circle" cx="50" cy="50" r="30" fill="yellow"></circle> 
      </svg> 
     </div> 
    </body> 

</html> 

这对我的作品在这两个FF 18和IE 9的恼人的是,FF和IE对这些事件都源不同的目标,与IE浏览器返回SVG作为目标的拖动事件,而FF返回圆圈。很烦人。

更新:我试过这个JSFiddle在Chrome 24中,它的工作原理。

+0

嗨,谢谢 - 我的主要目标是尝试看看我是否可以使用拖放事件来随机播放svg元素,只需简单地重新排序即可。最终,我认为答案可能不是为了这个目的而使用HTML5拖放。 –

0

tutorial是很好的理解本地拖放,有很多的例子。

但是,可能存在与SVG相关的特定问题。例如,请参阅Mozilla bug:“dragstart事件未在svg元素上触发”。

+0

嗨,谢谢,我刚开始阅读这篇教程。但这是一个很好的联系。 –