javascript 子元素允许拖放
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/24151886/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Child elements are allowing drag/drop
提问by Zerkeras
I'm having a weird issue with dragging and dropping in html5.
我在 html5 中拖放时遇到了一个奇怪的问题。
Panel A has a list of the type of elements you can drag. Panel B is where the elements are dragged. Panel C and D are other places you can drag elements, and you can drag and rearrange elements between Panels B, C and D.
面板 A 有一个您可以拖动的元素类型列表。面板 B 是拖动元素的位置。面板 C 和 D 是其他可以拖动元素的地方,您可以在面板 B、C 和 D 之间拖动和重新排列元素。
My issue is that I'm able to drag an element and drop it INSIDE of another element that's inside one of the panels, which I don't want the user to be able to do. The child elements of those panels don't have any kind of javascript or drag-related properties attached to them, and yet they are currently allowing elements to be dragged inside them.
我的问题是我能够拖动一个元素并将其放在一个面板内的另一个元素的内部,我不希望用户能够这样做。这些面板的子元素没有附加任何类型的 javascript 或与拖动相关的属性,但它们目前允许在其中拖动元素。
I've tried attaching "ondrop='return false;'" and "ondragover='return false;'", but neither has worked.
我试过附加“ondrop='return false;'”和“ondragover='return false;'”,但都没有奏效。
Surely there is a way to turn off the 'allow dragging into' property on an element?
当然有办法关闭元素上的“允许拖入”属性吗?
Here's my code:
这是我的代码:
<div id="elem-002" draggable="true" ondragstart="drag(event)">content</div>
The main panel:
主面板:
<div id="panel-b" ondrop="drop(event)" ondragover="allowDrop(event)">
<div id="elem-001" draggable="true" ondragstart="drag(event)">content</div>
</div>
The JS:
JS:
function allowDrop(ev) {
ev.preventDefault();
}
function drag(ev) {
ev.dataTransfer.setData("Text", ev.target.id);
}
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
Said another way: I'm able to drag my "elem-002" directly into "elem-001", an element that was already dragged in. This causing nesting of elements that I don't want to occur. How can I prevent this?
换句话说:我可以将我的“elem-002”直接拖入“elem-001”,这是一个已经被拖入的元素。这会导致我不想发生的元素嵌套。我怎样才能防止这种情况?
回答by lloiser
Basically you have to set the correct ev.dataTransfer.dropEffect
in allowDrop
. For your draggable
elements it should be "none"
(dropping is not allowed), and for everything else (or any other element where dropping is allowed) to "all"
基本上你必须ev.dataTransfer.dropEffect
在allowDrop
. 对于您的draggable
元素,它应该是"none"
(不允许删除),对于其他所有内容(或允许删除的任何其他元素)"all"
Further reading of dropEffect
进一步阅读dropEffect
Live example:
现场示例:
window.allowDrop = function(ev) {
ev.preventDefault();
if (ev.target.getAttribute("draggable") == "true")
ev.dataTransfer.dropEffect = "none"; // dropping is not allowed
else
ev.dataTransfer.dropEffect = "all"; // drop it like it's hot
};
window.drag = function(ev) {
ev.dataTransfer.setData("id", ev.target.id);
};
window.drop = function(ev) {
ev.preventDefault();
var id = ev.dataTransfer.getData("id");
var dragged = document.getElementById(id);
ev.target.appendChild(dragged);
dragged.className += " dropped";
};
.drag {
display: inline-block;
padding: 5px;
background: rgba(0, 0, 0, 0.2);
margin: 2px;
}
.dropzone {
background: #ccc;
padding: 5px;
margin-top: 10px;
}
<div id="first" class="drag" draggable="true" ondragstart="drag(event)">1</div>
<div id="second" class="drag" draggable="true" ondragstart="drag(event)">2</div>
<div class="dropzone" ondrop="drop(event)" ondragover="allowDrop(event)"><div id="third" class="drag dropped" draggable="true" ondragstart="drag(event)">3</div></div>
回答by Zerkeras
I'm not sure if this was the BEST solution, however I did come up with something.
我不确定这是否是最好的解决方案,但是我确实想出了一些办法。
I changed drop(ev) to this:
我将 drop(ev) 改为:
function drop(ev) {
ev.preventDefault();
if (!ev.target.getAttribute("ondrop"))
return false;
var data = ev.dataTransfer.getData("Text");
ev.target.appendChild(document.getElementById(data));
}
This or a variant of this prevents anything from being dropped into an element that has not had "ondrop" explicitly defined.
此或此的变体可防止将任何内容放入未明确定义“ondrop”的元素中。
回答by Dev Ops
I am using a custom drag and drop, mixing the mouse[down|move|up] of a element to be dragged with the drag[enter|over|leave] & drop on another element. And I am using Custom Events to trigger/fire/dispatch the drop event. That does not really make a difference to the issue at hand, just wanted to give context.
我正在使用自定义拖放,将要拖动的元素的鼠标 [down|move|up] 与拖放 [enter|over|leave] 和拖放到另一个元素上混合。我正在使用自定义事件来触发/触发/调度放置事件。这对手头的问题并没有真正的影响,只是想提供上下文。
Anyhoo, I was experiencing the same type of issue, and after searching for a while, and doing some debugging, I realised that the event.[target|srcElement] is actually the element which 'sent' the event. So what I ended up doing was to; reject any drop where the [target|srcElement] was the not the 'this' element of the event and where 'this' did not contain the [target|srcElement] (i.e. not one of its children), only then do I allow further processing;
Anyhoo,我遇到了同样类型的问题,在搜索了一段时间并进行了一些调试后,我意识到 event.[target|srcElement] 实际上是“发送”事件的元素。所以我最终做的是;拒绝 [target|srcElement] 不是事件的“this”元素并且“this”不包含 [target|srcElement](即不是其子元素之一)的任何丢弃,只有这样我才能进一步允许加工;
// Drop Event Handler
function dropEventHandler(event) {
event = event || window.event;
var target = event.target || event.srcElement;
if (this !== target && this.contains(target)) {
// Use if not a proper/normal event, this should stop any further
// processing of the event
// if (event.stopPropagation) event.stopPropagation(); // Standard model
// else event.cancelBubble = true; //IE
// Stops the default action of an element from happening
// Use the event.isDefaultPrevented() method to check whether
// the preventDefault() method was called for the event
if (event.preventDefault) event.preventDefault(); // Standard model
else event.returnValue = false; //IE
return false;
}
// Process drop event
}
Tested in Chrome, FF, Opera, IE Edge && IE 11 [emulation 7-11] on Windows 10, also IE v8.0.7601.17514 on Windows 7 [IE7 and IE8 Compatibility] modes tested.
在 Windows 10 上的 Chrome、FF、Opera、IE Edge && IE 11 [仿真 7-11] 中测试,也在 Windows 7 上测试了 IE v8.0.7601.17514 [IE7 和 IE8 兼容性] 模式。
回答by Glen Pierce
I've improved a bit on @Zerkeras answer by allowing the user to drop anywhere inside the drop target, but, rather than failing if the user happens to drop inside of an element inside the drop target, it just adjusts where the element gets dropped.
我对@Zerkeras 的回答进行了一些改进,允许用户在放置目标内的任何位置放置,但是,如果用户碰巧放置在放置目标内的元素内部,则不会失败,它只是调整元素放置的位置.
function drop(ev) {
ev.preventDefault();
var data = ev.dataTransfer.getData("text");
var i = 0;
var element = ev.target
while (!element.getAttribute("ondrop") && i < 3) {
console.log("recalibrating");
element = element.parentElement;
i++;
}
element.appendChild(document.getElementById(data));
}
Note, I've added an arbitrary 3 to escape from the while loop since I'm suspicious of while loops that aren't guaranteed to escape. This is pure paranoia on my part in this particular case, but it was very helpful when I was testing it.
请注意,我添加了一个任意 3 以从 while 循环中转义,因为我怀疑不能保证转义的 while 循环。在这种特殊情况下,这纯粹是我的偏执,但在我测试时它非常有帮助。
The reason I used the new variable element
was because directly modifying the ev.target
seemed impossible (I didn't think immutability worked in JavaScript? if anyone knows why this was, I'm curious). So my while loop was never exiting which is why you see my paranoid escape clause in there.
我使用新变量的原因element
是因为直接修改ev.target
似乎是不可能的(我不认为不变性在 JavaScript 中起作用?如果有人知道这是为什么,我很好奇)。所以我的 while 循环从未退出,这就是为什么你会在那里看到我的偏执转义子句。