如何在Firefox中拖动窗口以外的时候检测拖拽事件 [英] How to detect the dragleave event in Firefox when dragging outside the window

查看:131
本文介绍了如何在Firefox中拖动窗口以外的时候检测拖拽事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在拖动窗口之外Firefox不会正确触发拖曳事件:

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正在做,我知道这是可能的),但是我唯一可以想到的就是真的hackish。

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?

更新:

以下是我使用的代码:

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Drag and Drop Issue</title>
  <script src="http://code.jquery.com/jquery.js"></script>
</head>
<body>
  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.
  <script type="text/javascript">
    $(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>  
</body>
</html>


推荐答案

我找到了一个解决方案。问题不在于$ 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 添加到集合中,并从集合中删除了 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.

Phew,无论如何,这里是我最终使用的代码的基本版本。如果任何人有兴趣使用它,我已经把它放入一个简单的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.');
  }
});

这篇关于如何在Firefox中拖动窗口以外的时候检测拖拽事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆