我尝试创建文件拖放处理程序(将文件拖到浏览器窗口中,用于上传)。
出于某种原因,当我将拖放监听器绑定到$("body")
而不是绑定到正文中的$("div")
时,事件连续多次触发,有时甚至不停(看似循环) 。可能导致这种情况的原因是什么?
以下是代码的精简版:http://jsfiddle.net/WxMwK/9/
var over = false;
$("body")
.on("dragover", function(e){
e.preventDefault();
if (! over) {
over = true;
$("ul").append($("<li/>").text("dragover"));
}
})
.on("dragleave", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("dragleave"));
}
})
.on("drop", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("drop"));
}
});
要测试:将文件拖到橙色区域,您会看到连续多次触发事件。
答案 0 :(得分:12)
anon(大多数)是正确的。简单地说:当鼠标在放置目标内的元素的边缘上移动时,你会得到{{1>}光标下的元素和dropenter
表示光标之前的元素。绝对任何后代都会发生这种情况。
您无法检查与dropleave
相关联的元素,因为如果您将鼠标从移动到一个子元素,您将会为孩子获得dragleave
,然后为目标获得dropenter
!这有点荒谬,我根本看不出这是一个有用的设计。
这是我前段时间提出的一个基于jQuery的糟糕解决方案。
dropleave
这个伎俩依赖于两个事实:
var $drop_target = $(document.body);
var within_enter = false;
$drop_target.bind('dragenter', function(evt) {
// Default behavior is to deny a drop, so this will allow it
evt.preventDefault();
within_enter = true;
setTimeout(function() { within_enter = false; }, 0);
// This is the part that makes the drop area light up
$(this).addClass('js-dropzone');
});
$drop_target.bind('dragover', function(evt) {
// Same as above
evt.preventDefault();
});
$drop_target.bind('dragleave', function(evt) {
if (! within_enter) {
// And this makes it un-light-up :)
$(this).removeClass('js-dropzone');
}
within_enter = false;
});
// Handle the actual drop effect
$drop_target.bind('drop', function(evt) {
// Be sure to reset your state down here
$(this).removeClass('js-dropzone');
within_enter = false;
evt.preventDefault();
do_whatever(evt.originalEvent.dataTransfer.files);
});
和dragenter
将按顺序排列目标元素 。dragleave
和dragenter
一起排队。所以这就是发生的事情。
dragleave
事件中,我设置了一些共享变量来指示拖动动作尚未完成解析。dragenter
来立即更改该变量。setTimeout
的事件处理程序。dragleave
发现它与同一目标元素上的dragleave
配对,则表示鼠标必须已从某个后代移动到其他后代。否则,鼠标实际上是离开目标元素。dragenter
最终在零秒后解析,在另一个事件发生之前设置回变量。我想不出更简单的方法。
答案 1 :(得分:0)
您正在为BODY
,dragover
和dragleave
的{{1}} HTMLElement添加听众。
当你继续拖动DIV时,有一个drop
被触发,因为鼠标不再拖过BODY,而是越过DIV。
其次,由于您没有停止dragleave
上的气泡事件(未设置任何侦听器),因此DIV
上的诈骗者正在向DIV
发出警告。
如果我恢复:
鼠标进入身体(在dragover中)
- &GT; 火力拖过(身体)
鼠标在体内输入DIV
- &GT; 火力拖动(BODY)
- &GT; 火力拖拽(DIV) - &gt; 事件冒泡 - &gt; 火力拖累(BODY)
BODY
和mouseover
存在类似问题,使用mouseout
和mouseenter
修复了此问题。
您可以使用mouseleave
事件类型尝试相同的代码。如果它不起作用,您可以检查dragenter
是否为event.target
。此测试可以帮助跳过不需要的拖动事件。
答案 2 :(得分:0)
var over = false;
$("body")
.on("dragover", function(e){
e.preventDefault();
if (! over) {
over = true;
$("ul").append($("<li/>").text("dragover"));
}
})
.on("dragleave", function(e){
e.preventDefault();
if (over) {
over = false;
$("ul").append($("<li/>").text("dragleave"));
}
})
.on("drop", function(e){
e.preventDefault();
if (over) {
over = false;
}
});
答案 3 :(得分:0)
或者您可以使用stop();
来停止动画构建