2013-01-20 79 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

嗨,謝謝,我剛開始閱讀這篇教程。但這是一個很好的聯繫。 –