我遇到的问题是,一个元素的dragleave事件是在悬停该元素的子元素时触发的。同样,当再次悬停回父元素时,dragenter不会被触发。
我做了一个简化的小提琴:http://jsfiddle.net/pimvdb/HU6Mk/1/。
HTML:
<div id="drag" draggable="true">drag me</div>
<hr>
<div id="drop">
drop here
<p>child</p>
parent
</div>
使用以下JavaScript:
$('#drop').bind({
dragenter: function() {
$(this).addClass('red');
},
dragleave: function() {
$(this).removeClass('red');
}
});
$('#drag').bind({
dragstart: function(e) {
e.allowedEffect = "copy";
e.setData("text/plain", "test");
}
});
它应该做的是,当拖拽一些东西时,通过将drop div设置为红色来通知用户。这是可行的,但是如果你拖动到p子元素中,拖动键就会触发,div就不再是红色了。移动回下拉div也不会使它再次变红。有必要完全移出拖放div,并再次拖回它,使其变为红色。
是否有可能阻止dragleave在拖动到子元素时发射?
2017年更新:TL;DR,查找CSS指针事件:无;如@ h.d.所述。在现代浏览器和IE11中都能运行。
当鼠标指针离开目标容器的拖动区域时触发"dragleave"事件。
这很有道理,因为在许多情况下,只有父母可以放弃,而不是后代。
我认为event. stoppropagation()应该处理这种情况,但似乎它没有做到这一点。
上面提到的一些解决方案似乎在大多数情况下都有效,但在那些不支持dragenter / dragleave事件的情况下失败了,比如iframe。
解决方法之一是检查事件。并验证它是否驻留在容器中,然后忽略dragleave事件,就像我在这里所做的那样:
function isAncestor(node, target) {
if (node === target) return false;
while(node.parentNode) {
if (node.parentNode === target)
return true;
node=node.parentNode;
}
return false;
}
var container = document.getElementById("dropbox");
container.addEventListener("dragenter", function() {
container.classList.add("dragging");
});
container.addEventListener("dragleave", function(e) {
if (!isAncestor(e.relatedTarget, container))
container.classList.remove("dragging");
});
你可以在这里找到一把能用的小提琴!
在花了这么多小时后,我得到的建议完全按照预期工作。我只想在文件被拖拽时提供提示,而文档拖拽,拖拽会在Chrome浏览器上引起痛苦的闪烁。
这就是我解决它的方法,也为用户提供了适当的提示。
$(document).on('dragstart dragenter dragover', function(event) {
// Only file drag-n-drops allowed, http://jsfiddle.net/guYWx/16/
if ($.inArray('Files', event.originalEvent.dataTransfer.types) > -1) {
// Needed to allow effectAllowed, dropEffect to take effect
event.stopPropagation();
// Needed to allow effectAllowed, dropEffect to take effect
event.preventDefault();
$('.dropzone').addClass('dropzone-hilight').show(); // Hilight the drop zone
dropZoneVisible= true;
// http://www.html5rocks.com/en/tutorials/dnd/basics/
// http://api.jquery.com/category/events/event-object/
event.originalEvent.dataTransfer.effectAllowed= 'none';
event.originalEvent.dataTransfer.dropEffect= 'none';
// .dropzone .message
if($(event.target).hasClass('dropzone') || $(event.target).hasClass('message')) {
event.originalEvent.dataTransfer.effectAllowed= 'copyMove';
event.originalEvent.dataTransfer.dropEffect= 'move';
}
}
}).on('drop dragleave dragend', function (event) {
dropZoneVisible= false;
clearTimeout(dropZoneTimer);
dropZoneTimer= setTimeout( function(){
if( !dropZoneVisible ) {
$('.dropzone').hide().removeClass('dropzone-hilight');
}
}, dropZoneHideDelay); // dropZoneHideDelay= 70, but anything above 50 is better
});
这里是最简单的跨浏览器解决方案(认真地说):
Jsfiddle <——尝试将一些文件拖到框中
你可以这样做:
var dropZone= document.getElementById('box');
var dropMask = document.getElementById('drop-mask');
dropZone.addEventListener('dragover', drag_over, false);
dropMask.addEventListener('dragleave', drag_leave, false);
dropMask.addEventListener('drop', drag_drop, false);
简单地说,你在拖拽区域内创建了一个“蒙版”,宽度和高度是继承的,位置是绝对的,这将显示拖拽开始的时间。
因此,在显示该蒙版之后,您可以通过附加其他拖放事件来实现这一技巧。
离开或掉落后,你只需将面具再次隐藏起来。
简单,无并发症。
(奥林匹克广播服务公司。: Greg Pettit的建议——你必须确保蒙版悬浮在整个盒子上,包括边框)
我知道这是一个老问题,但我想补充我的偏好。我处理这个通过添加类触发css:后元素在更高的z-index然后你的内容。这样可以过滤掉所有的垃圾。
.droppable{
position: relative;
z-index: 500;
}
.droppable.drag-over:after{
content: "";
display:block;
position:absolute;
left:0;
right:0;
top:0;
bottom:0;
z-index: 600;
}
然后只需在您的第一个dragenter事件上添加拖拽类,并且不再有子元素触发该事件。
dragEnter(event){
dropElement.classList.add('drag-over');
}
dragLeave(event){
dropElement.classList.remove('drag-over');
}