Javascript - 双文件拖动事件触发

标签 javascript jquery drag-and-drop

我正在尝试创建文件拖放处理程序(将文件拖到浏览器窗口中,用于上传)。

出于某种原因,当我将拖放监听器绑定(bind)到 $("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"));
        }
    }); 

测试:将文件拖到橙色区域,您会看到事件连续触发多次。

最佳答案

匿名者(大部分)是正确的。简而言之:当鼠标移过放置目标内元素的边缘时,您会得到光标下元素dropenter > 和之前光标下的元素的 dropleave。这绝对发生在任何后代身上。

您无法检查与 dragleave 关联的元素,因为如果您将鼠标从您的放置目标移动到一个子元素,您将为 child 获得一个 dropenter,然后为目标获得一个 dropleave!这有点荒谬,我根本看不出这是一个有用的设计。

这是我不久前想出的一个糟糕的基于 jQuery 的解决方案。

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);
});

这个技巧依赖于两个事实:

  • 当您将鼠标从孙元素移动到子元素时,dragenterdragleave 都将排队等待目标元素 —按此顺序.
  • dragenterdragleave 一起排队。

这就是发生的事情。

  • dragenter 事件中,我设置了一些共享变量来指示拖动运动尚未完成解析。
  • 我使用延迟为零的 setTimeout 立即将该变量改回。
  • 但是!因为这两个事件在同一时间排队,所以在两个事件完成解析之前,浏览器不会运行任何计划的功能。所以接下来发生的事情是 dragleave 的事件处理程序。
  • 如果 dragleave 发现它与同一目标元素上的 dragenter 配对,则意味着鼠标必须已从某个后代移动给其他一些后代。否则,鼠标实际上离开了目标元素。
  • 然后 setTimeout 最终在 0 秒后解析,在另一个事件出现之前设置回变量。

我想不出更简单的方法。

关于Javascript - 双文件拖动事件触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14392293/

相关文章:

javascript - 检测到 UI Grid v3.1.0 列自动宽度问题

javascript - 格式化 jquery.datetimepicker 文本字段

javascript - 年份转换功能

javascript - 如何将数组作为 URL 参数传递?

javascript - 当 jQuery ajax 在 js 函数内调用时,动画在 IE 中不起作用

ios - 使用 iOS 9 的多任务处理,我的应用程序可以接收来自另一个应用程序的拖动内容吗?

javascript - IE 10拖放上传给出空dataTransfer

jquery - 在使用 jquery validate 时,我应该对这个特定的 css 做些什么更改以防止错误?

javascript - 将 CSS 类添加到数组中的单个元素

javascript - 使用HTML5原生拖放时如何限制移动?