如何在窗外拖动时检测 Firefox 中的 dragleave 事件
How to detect the dragleave event in Firefox when dragging outside the window
Firefox 在窗外拖动时无法正确触发 dragleave 事件:
https://bugzilla.mozilla.org/show_bug.cgi?id=665704
https://bugzilla.mozilla.org/show_bug.cgi?id=656164
我正在尝试为此开发一种解决方法(我知道这是可能的,因为 Gmail 正在这样做),但我唯一能想到的东西似乎真的很黑客。
当拖动到窗口外时,一种方法是等待dragover
事件停止触发(因为dragover
在拖放操作期间不断触发)。这是我的做法:
var timeout;
function dragleaveFunctionality() {
// do stuff
}
function firefoxTimeoutHack() {
clearTimeout(timeout);
timeout = setTimeout(dragleaveFunctionality, 200);
}
$(document).on('dragover', firefoxTimeoutHack);
此代码实质上是一遍又一遍地创建和清除超时。除非 dragover
事件停止触发,否则不会达到 200 毫秒超时。
虽然这有效,但我不喜欢为此目的使用超时的想法。感觉不对劲。这也意味着在"dropzone"样式消失之前会有轻微的滞后。
我的另一个想法是检测鼠标何时离开窗口,但是在拖放操作期间,通常的方法似乎不起作用。
有没有人有更好的方法来做到这一点?
更新:
这是我使用的代码:
$(function() {
var counter = 0;
$(document).on('dragenter', function(e) {
counter += 1;
console.log(counter, e.target);
});
$(document).on('dragleave', function(e) {
counter -= 1;
console.log(counter, e.target);
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<p>Open up the console and look at what number is reporting when dragging files in and out of the window. The number should always be 0 when leaving the window, but in Firefox it's not.</p>
我找到了解决方案。问题不在于dragleave
事件没有触发;相反,dragenter
事件在首次将文件拖入窗口时触发两次(有时在拖动某些元素时也会触发)。我最初的解决方案是使用计数器来跟踪最终dragleave
事件发生的时间,但dragenter
事件的双重触发使计数混乱。(为什么我不能听你问dragleave
?好吧,因为dragleave
的功能与mouseout
非常相似,因为它不仅在离开元素时触发,而且在进入子元素时触发。因此,当dragleave
触发时,您的鼠标很可能仍在原始元素的范围内。
我想出的解决方案是跟踪dragenter
和dragleave
触发了哪些元素。由于事件会传播到文档,因此侦听特定元素的dragenter
和dragleave
不仅会捕获该元素上的事件,还会捕获其子元素上的事件。
因此,我创建了一个 jQuery 集合$()
来跟踪哪些事件在哪些元素上触发。每当触发 dragenter 时,我都会将event.target
添加到集合中,每当发生 dragleave 时,我都会从集合中删除event.target
。这个想法是,如果集合为空,则意味着我实际上已经离开了原始元素,因为如果我输入一个子元素,至少一个元素(子元素)仍将在jQuery集合中。最后,当触发 drop
事件时,我想将集合重置为空,以便在下一个dragenter
事件发生时准备就绪。
jQuery还节省了大量额外的工作,因为它会自动执行重复检查,因此即使Firefox错误地双重调用dragenter
,也不会添加两次event.target
。
呼,无论如何,这是我最终使用的代码的基本版本。我已经把它放到一个简单的jQuery插件中,如果其他人有兴趣使用它。基本上,您在任何元素上调用.draghover
,draghoverstart
在首次拖动到元素时触发,draghoverend
在拖动实际离开元素时触发。
// The plugin code
$.fn.draghover = function(options) {
return this.each(function() {
var collection = $(),
self = $(this);
self.on('dragenter', function(e) {
if (collection.length === 0) {
self.trigger('draghoverstart');
}
collection = collection.add(e.target);
});
self.on('dragleave drop', function(e) {
collection = collection.not(e.target);
if (collection.length === 0) {
self.trigger('draghoverend');
}
});
});
};
// Now that we have a plugin, we can listen for the new events
$(window).draghover().on({
'draghoverstart': function() {
console.log('A file has been dragged into the window.');
},
'draghoverend': function() {
console.log('A file has been dragged out of window.');
}
});
没有 jQuery
要在没有jQuery的情况下处理这个问题,你可以做这样的事情:
// I want to handle drag leaving on the document
let count = 0
onDragEnter = (event) => {
if (event.currentTarget === document) {
count += 1
}
}
onDragLeave = (event) => {
if (event.currentTarget === document) {
count += 0
}
if (count === 0) {
// Handle drag leave.
}
}
根据您希望完成的操作,您可以使用仅在 Firefox 中可用的:-moz-drag-over
伪类来解决此问题,该伪类允许您对拖动到元素上的文件做出反应。
看看这个简单的演示 http://codepen.io/ryanseddon/pen/Ccsua
.dragover {
background: red;
width: 500px;
height: 300px;
}
.dragover:-moz-drag-over {
background: green;
}
受到@PhilipWalton代码的启发,我简化了jQuery插件代码。
$.fn.draghover = function(fnIn, fnOut) {
return this.each(function() {
var n = 0;
$(this).on('dragenter', function(e) {
(++n, n==1) && fnIn && fnIn.call(this, e);
}).on('dragleave drop', function(e) {
(--n, n==0) && fnOut && fnOut.call(this, e);
});
});
};
现在你可以使用 jquery 插件,比如 jquery 悬停方法:
// Testing code 1
$(window).draghover(function() {
console.log('into window');
}, function() {
console.log('out of window');
});
// Testing code 2
$('#d1').draghover(function() {
console.log('into #d1');
}, function() {
console.log('out of #d1');
});
唯一对我有用的解决方案,花了我几次时间,希望这对某人有所帮助!
注意 克隆时,需要使用事件和数据进行深度克隆:
.HTML:
<div class="dropbox"><p>Child element still works!</p></div>
<div class="dropbox"></div>
<div class="dropbox"></div>
jQuery
$('.dropbox').each(function(idx, el){
$(this).data("counter" , 0);
});
$('.dropbox').clone(true,true).appendTo($('body');
$('dropbox').on({
dragenter : function(e){
$(this).data().counter++;
<!-- YOUR CODE HERE -->
},
dragleave: function(e){
$(this).data().counter--;
if($(this).data().counter === 0)
<!-- THEN RUN YOUR CODE HERE -->
}
});
addEvent(document, "mouseout", function(e) {
e = e ? e : window.event;
var from = e.relatedTarget || e.toElement;
if (!from || from.nodeName == "HTML") {
// stop your drag event here
// for now we can just use an alert
alert("left window");
}
});
这是从如何检测鼠标何时离开窗口?复制的。 addEvent 只是跨浏览器 addEventListener。
- 重载JS'firefox中的对象原型
- ascii输入键通过firefox中的javascript返回0
- onbeforeunload和asp:Safari和FireFox中的更新面板
- firefox中的Javascript事件范围问题
- js禁用firefox中的退格功能
- firefox中的CSS动画不起作用
- Firefox中的JavaScript事件参数
- 如何使用javascript禁用firefox中的硬件加速
- 为什么parseInt()比Firefox中的*1慢得多
- 如何在javascript中获取Android Firefox中的menuID
- 桌面firefox中的偏移值各不相同
- javascript代码,用于删除firefox中的空白,但在IE和chrome中无法正常工作
- 在 chrome 或 Firefox 中的调试控制台对.js文件运行 JSLint
- 无法将字体系列设置为“”;Arial黑色”;通过Firefox中的JavaScript
- FIREFOX中的粘性菜单错误
- 用于获取<输入类型=文件>只返回firefox中的文件名
- firefox中的setTimeout延迟
- 回溯历史后,Firefox中的Ajax调用缓存
- 使javascript在firefox中的插件javascript之后执行
- angularJS在Firefox中的糟糕性能