如何像Gmail一样检测进入和离开窗口的HTML5拖动事件?

Hei*_*ann 23 html5 gmail drag-and-drop

我希望能够在携带文件的光标进入浏览器窗口后立即突出显示丢弃区域,就像Gmail一样.但我不能让它发挥作用,我觉得我只是错过了一些非常明显的东西.

我一直在努力做这样的事情:

this.body = $('body').get(0)
this.body.addEventListener("dragenter", this.dragenter, true)
this.body.addEventListener("dragleave", this.dragleave, true)`
Run Code Online (Sandbox Code Playgroud)

但是,每当光标移过和移出除BODY之外的元素时,它都会触发事件,这是有道理的,但绝对不起作用.我可以在所有东西上面放置一个元素,覆盖整个窗口并检测到它,但这是一种可怕的方式.

我错过了什么?

Tyl*_*ler 23

我用超时解决了它(不是吱吱作响,但是有效):

var dropTarget = $('.dropTarget'),
    html = $('html'),
    showDrag = false,
    timeout = -1;

html.bind('dragenter', function () {
    dropTarget.addClass('dragging');
    showDrag = true; 
});
html.bind('dragover', function(){
    showDrag = true; 
});
html.bind('dragleave', function (e) {
    showDrag = false; 
    clearTimeout( timeout );
    timeout = setTimeout( function(){
        if( !showDrag ){ dropTarget.removeClass('dragging'); }
    }, 200 );
});
Run Code Online (Sandbox Code Playgroud)

我的例子使用jQuery,但没有必要.以下是对正在发生的事情的总结:

  • 将flag(showDrag)设置为trueon dragenterdragoverhtml(或body)元素.
  • dragleave标志设置false.然后设置一个简短的超时以检查该标志是否仍为false.
  • 理想情况下,跟踪超时并在设置下一个超时之前将其清除.

这样,每个dragleave事件都为DOM提供了足够的时间dragover来重置标志.我们关心的真实,最终 dragleave将看到旗帜仍然是假的.


cin*_*tic 9

不知道它适用于所有情况,但在我的情况下它工作得很好

$('body').bind("dragleave", function(e) {
   if (!e.originalEvent.clientX && !e.originalEvent.clientY) {
      //outside body / window
   }
});
Run Code Online (Sandbox Code Playgroud)

  • 这并不总能成功检测到拖动的结束(EG:从浏览器外部拖动并放到chrome中的'downloads'栏上的文件不会发送带有0,0的dragleave作为clientX/Y (3认同)

ile*_*ile 7

添加事件document似乎工作?使用Chrome,Firefox,IE 10进行测试.

获得该事件的第一个元素是<html>,我认为应该没问题.

var dragCount = 0,
    dropzone = document.getElementById('dropzone');

function dragenterDragleave(e) {
  e.preventDefault();
  dragCount += (e.type === "dragenter" ? 1 : -1);
  if (dragCount === 1) {
    dropzone.classList.add('drag-highlight');
  } else if (dragCount === 0) {
    dropzone.classList.remove('drag-highlight');
  }
};

document.addEventListener("dragenter", dragenterDragleave);
document.addEventListener("dragleave", dragenterDragleave);
Run Code Online (Sandbox Code Playgroud)


Mva*_*est 1

您的第三个参数addEventListenertrue,它使侦听器在捕获阶段运行(有关可视化,请参阅http://www.w3.org/TR/DOM-Level-3-Events/#event-flow )。这意味着它将捕获针对其后代的事件 - 以及针对页面上所有元素的正文的事件。在您的处理程序中,您必须检查触发它们的元素是否是主体本身。我会给你我非常肮脏的做法。如果有人知道一种实际比较元素的更简单的方法,我很乐意看到它。

this.dragenter = function() {
    if ($('body').not(this).length != 0) return;
    ... functional code ...
}
Run Code Online (Sandbox Code Playgroud)

这会找到主体并this从找到的元素集中删除。如果集合不为空,则this主体也不是空的,所以我们不喜欢这样并返回。如果thisbody,则该集合将为空并且代码将执行。

您可以尝试使用简单的方法if (this == $('body').get(0)),但这可能会失败。