使用 javascript 进行 HTML5 拖放 DOM 操作
Posted
技术标签:
【中文标题】使用 javascript 进行 HTML5 拖放 DOM 操作【英文标题】:HTML5 drag and drop DOM manipulation with javascript 【发布时间】:2013-01-03 19:38:14 【问题描述】:我正在尝试使用本机拖放事件重新排序 DOM SVG 元素。下面的代码在 Firefox 中似乎可以工作(带有一些奇怪的图像效果),在 Chrome 中工作的次数有限(2 或 3 次拖放重新排序工作,然后它似乎挂起),在 IE 中根本不是很好。我最好的猜测是,我没有正确考虑所讨论的事件,某种类型的重置。或者可能以这种方式使用没有 dataTransfer 的拖动事件是不正确的。我的目标是在没有库的情况下理解这种类型的函数,但在最基本的层面上对 DOM 函数、javascript、html 和 CSS 有一个更清晰的理解。我很容易在该列表中的任何地方出错。
<!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" >
<circle cx="50" cy="50" r="30" fill="blue"></circle>
</svg>
<svg id="s2" draggable="yes" >
<circle cx="50" cy="50" r="30" fill="red"></circle>
</svg>
<svg id="s3" draggable="yes" >
<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>
【问题讨论】:
请注意,IE9 中的 dnd_svg 函数中存在 javascript 错误。 var parent_c2 = c2.parentElement ? c2.parentElement : c2.parentNode;为我解决了。见jsfiddle.net/nrNSS。 【参考方案1】:见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" 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 返回圆圈。很烦人。
更新:我在 Chrome 24 中尝试了这个 JSFiddle,它可以工作。
【讨论】:
嗨,谢谢 - 我的主要目标是尝试看看我是否可以使用拖放事件来打乱 svg 元素,只是一个简单的重新排序。最终,我认为答案可能是不为此目的使用 HTML5 拖放。【参考方案2】:这个tutorial 很好理解原生拖放,有很多例子。
但是,可能存在与 SVG 相关的特定问题。例如,请参见 Mozilla bug:“dragstart 事件未在 svg 元素上触发”。
【讨论】:
嗨,谢谢,我在开始这个教程时已经查看了该教程。但这是一个很好的链接。以上是关于使用 javascript 进行 HTML5 拖放 DOM 操作的主要内容,如果未能解决你的问题,请参考以下文章