問題描述
Firefox 在窗口外拖動時沒有正確觸發 dragleave 事件:
Firefox doesn't properly trigger the dragleave event when dragging outside of the window:
https://bugzilla.mozilla.org/show_bug.cgi?id=665704
https://bugzilla.mozilla.org/show_bug.cgi?id=656164
我正在嘗試為此開發一種解決方法(我知道這是可能的,因為 Gmail 正在這樣做),但我唯一能想到的似乎真的很老套.
I'm trying to develop a workaround for this (which I know is possible because Gmail is doing it), but the only thing I can come up with seems really hackish.
知道何時拖到窗口外的一種方法是等待 dragover
事件停止觸發(因為 dragover
在拖放操作期間會不斷觸發).以下是我的做法:
One way of knowing when dragging outside the window has occurred it to wait for the dragover
event to stop firing (because dragover
fires constantly during a drag and drop operation). Here's how I'm doing that:
var timeout;
function dragleaveFunctionality() {
// do stuff
}
function firefoxTimeoutHack() {
clearTimeout(timeout);
timeout = setTimeout(dragleaveFunctionality, 200);
}
$(document).on('dragover', firefoxTimeoutHack);
這段代碼本質上是一次又一次地創建和清除超時.除非 dragover
事件停止觸發,否則不會達到 200 毫秒超時.
This code is essentially creating and clearing a timeout over and over again. The 200 millisecond timeout will not be reached unless the dragover
event stops firing.
雖然這可行,但我不喜歡為此目的使用超時的想法.感覺不對.這也意味著在dropzone"樣式消失之前會有一點延遲.
While this works, I don't like the idea of using a timeout for this purpose. It feels wrong. It also means there's a slight lag before the "dropzone" styling goes away.
我的另一個想法是檢測鼠標何時離開窗口,但是在拖放操作期間執行此操作的正常方法似乎不起作用.
The other idea I had was to detect when the mouse leaves the window, but the normal ways of doing that don't seem to work during drag and drop operations.
有沒有人有更好的方法來做到這一點?
Does anyone out there have a better way of doing this?
更新:
這是我正在使用的代碼:
Here's the code I am using:
$(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
事件在第一次將文件拖入窗口時觸發了兩次(另外有時在拖動某些元素時).我最初的解決方案是使用計數器來跟蹤最終的 dragenter
事件的雙重觸發卻弄亂了計數.(為什么我不能只聽你問的 dragleave
?好吧,因為 dragleave
的功能與 mouseout
非常相似,因為它不僅會在以下情況下觸發離開元素,但在進入子元素時也一樣.因此,當 dragleave
觸發時,您的鼠標很可能仍然在原始元素的范圍內.)
I've found a solution. The problem was not so much that the dragleave
event wasn't firing; rather, the dragenter
event was firing twice when first dragging a file into the window (and additionally sometimes when dragging over certain elements). My original solution was to use a counter to track when the final dragleave
event was occuring, but the double firing of dragenter
events was messing up the count. (Why couldn't I just listen for dragleave
you ask? Well, because dragleave
functions very similarly to mouseout
in that it fires not only when leaving the element but also when entering a child element. Thus, when dragleave
fires, your mouse may very well still be within the bounds of the original element.)
我想出的解決方案是跟蹤哪些元素 dragenter
和 dragleave
已被觸發.由于事件會向上傳播到文檔,因此在特定元素上偵聽 dragenter
和 dragleave
不僅會捕獲該元素上的事件,還會捕獲其子元素上的事件.
The solution I came up with was to keep track of which elements dragenter
and dragleave
had been triggered on. Since events propagate up to the document, listening for dragenter
and dragleave
on a particular element will capture not only events on that element but also events on its children.
所以,我創建了一個 jQuery 集合 $()
來跟蹤在哪些元素上觸發了哪些事件.每當 dragenter 被觸發時,我就將 event.target
添加到集合中,并且每當 dragleave 發生時,我就從集合中刪除 event.target
.這個想法是,如果集合為空,則意味著我實際上已經離開了原始元素,因為如果我輸入的是子元素,則至少一個元素(子元素)仍會在 jQuery 集合中.最后,當 drop
事件被觸發時,我想將集合重置為空,以便在下一個 dragenter
事件發生時準備就緒.
So, I created a jQuery collection $()
to keep track of what events were fired on what elements. I added the event.target
to the collection whenever dragenter was fired, and I removed event.target
from the collection whenever dragleave happened. The idea was that if the collection were empty it would mean I had actually left the original element because if I were entering a child element instead, at least one element (the child) would still be in the jQuery collection. Lastly, when the drop
event is fired, I want to reset the collection to empty, so it's ready to go when the next dragenter
event occurs.
jQuery 還節省了很多額外的工作,因為它會自動進行重復檢查,因此 event.target
不會被添加兩次,即使 Firefox 錯誤地重復調用 dragenter代碼>.
jQuery also saves a lot of extra work because it automatically does duplicate checking, so event.target
doesn't get added twice, even when Firefox was incorrectly double-invoking dragenter
.
唷,無論如何,這是我最終使用的代碼的基本版本.如果其他人有興趣使用它,我已將其放入一個簡單的 jQuery 插件中.基本上,你在任何元素上調用 .draghover
,當第一次拖入元素時觸發 draghoverstart
,一旦拖入元素就會觸發 draghoverend
居然離開了.
Phew, anyway, here's a basic version of the code I ended up using. I've put it into a simple jQuery plugin if anyone else is interested in using it. Basically, you call .draghover
on any element, and draghoverstart
is triggered when first dragging into the element, and draghoverend
is triggered once the drag has actually left it.
// 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 的情況下處理此問題,您可以執行以下操作:
To handle this without jQuery you can do something like this:
// 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中的dragleave事件的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!