我遇到的问题是,一个元素的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中都能运行。
不确定这是否跨浏览器,但我在Chrome中测试,它解决了我的问题:
我想拖放一个文件在整个页面,但我的dragleave被解雇时,我拖过子元素。我的解决方法是查看鼠标的x和y:
我有一个div覆盖我的整个页面,当页面加载我隐藏它。
当你拖拽文件时,我显示它,当你拖拽到父文件时,它处理它,当你离开父文件时,我检查x和y。
$('#draganddrop-wrapper').hide();
$(document).bind('dragenter', function(event) {
$('#draganddrop-wrapper').fadeIn(500);
return false;
});
$("#draganddrop-wrapper").bind('dragover', function(event) {
return false;
}).bind('dragleave', function(event) {
if( window.event.pageX == 0 || window.event.pageY == 0 ) {
$(this).fadeOut(500);
return false;
}
}).bind('drop', function(event) {
handleDrop(event);
$(this).fadeOut(500);
return false;
});
在这个问题被提出之后已经有一段时间了,并且提供了很多解决方案(包括丑陋的黑客)。
我设法解决了我最近遇到的同样的问题,感谢这个答案中的答案,并认为它可能对来到这个页面的人有帮助。
整个思想就是存储事件。每当对任何父元素或子元素调用时,ondrageenter中的目标。然后在ondragleave检查当前目标(event.target)是否等于你在ondragenter中存储的对象。
这两者匹配的唯一情况是当您的拖动离开浏览器窗口时。
这样工作正常的原因是当鼠标离开一个元素(例如el1)并进入另一个元素(例如el2)时,首先是el2。调用Ondragenter,然后调用el1.ondragleave。仅当拖动离开/进入浏览器窗口时,事件。目标将是“在两个el2。Ondragenter和el1.ondragleave。
这是我的工作样本。我已经在IE9+、Chrome、Firefox和Safari上进行了测试。
(function() {
var bodyEl = document.body;
var flupDiv = document.getElementById('file-drop-area');
flupDiv.onclick = function(event){
console.log('HEy! some one clicked me!');
};
var enterTarget = null;
document.ondragenter = function(event) {
console.log('on drag enter: ' + event.target.id);
enterTarget = event.target;
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-drag-on-top';
return false;
};
document.ondragleave = function(event) {
console.log('on drag leave: currentTarget: ' + event.target.id + ', old target: ' + enterTarget.id);
//Only if the two target are equal it means the drag has left the window
if (enterTarget == event.target){
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-no-drag';
}
};
document.ondrop = function(event) {
console.log('on drop: ' + event.target.id);
event.stopPropagation();
event.preventDefault();
flupDiv.className = 'flup-no-drag';
return false;
};
})();
这是一个简单的html页面:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Multiple File Uploader</title>
<link rel="stylesheet" href="my.css" />
</head>
<body id="bodyDiv">
<div id="cntnr" class="flup-container">
<div id="file-drop-area" class="flup-no-drag">blah blah</div>
</div>
<script src="my.js"></script>
</body>
</html>
使用适当的样式,我所做的是使内部div (#file-drop area)在文件被拖到屏幕时变得更大,以便用户可以轻松地将文件放到适当的位置。
在花了这么多小时后,我得到的建议完全按照预期工作。我只想在文件被拖拽时提供提示,而文档拖拽,拖拽会在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
});