7

问题

我刚刚完成了一项功能,用户可以将文件拖到浏览器中并放在支持的文件上传插件上,该插件会处理拖放。

然而,为了给用户一个提示,他们甚至可以在第一时间放下东西,我已经实现了一个dragover事件来显示div类似于“Drop Here”的内容。反过来,这会隐藏div具有“选择文件...”按钮的按钮,并替换它,直到用户停止拖动。

但似乎,当我实现这个时,在目标区域上拖动会导致闪烁。要清楚:

  • div显示“选择文件”界面。
  • 拖动的项目(或拖动的选定文本);显示“放在这里”。
  • 项目拖到“放在这里”区域;闪烁开始。

此外:

  • Opera 12 或 Firefox 16 没有问题。
  • 这个问题在 Chrome 23 和 Safari 5 中非常明显。
  • 该问题部分存在于 IE 9 中(IE 10 未经测试);它闪烁约 5 秒钟,然后停止。

jsFiddle

(警告:小提琴非常粗糙。)

只需选择一些文本并将其拖到蓝色框上,您就会看到会发生什么;很明显它不应该表现出的行为。

小提琴中使用的代码

var $dropTarget = $("#container");
$(document).bind("dragover", function(e) {
    if ($dropTarget.hasClass("highlight"))
        return;

    $dropTarget.addClass("highlight");
    $dropTarget.find("[name='drop']").show();
    $dropTarget.find("[name='drag']").hide();
}).bind("dragleave drop", function(e) {
    if (!$dropTarget.hasClass("highlight"))
        return;

    $dropTarget.removeClass("highlight");
    $dropTarget.find("[name='drop']").hide();
    $dropTarget.find("[name='drag']").show();
});​

我的解决方案...?

老实说,我不知道该尝试什么。没有关于dragoveror行为的大量文档dragleave,我什至不知道为什么会这样,所以我什至无法开始调试它。我觉得dragover应该只触发一次,但即使在屏幕上拖动也会一遍又一遍地触发它。

我查看了谷歌图片和谷歌联系人的拖放行为,但他们的代码被完全缩小且不可读,我什至找不到任何指定的“拖动”行为。

那么,这种看似奇怪的行为有什么解决办法吗?如果这是我怀疑的 WebKit 中的错误,是否有一些出色的解决方法和/或我可以使用的 hack?

感谢大家的时间!

4

3 回答 3

24

经过一个多小时的搜索,我找到了一个有类似问题的人。似乎 Chrome 和 Safari(至少 5 个)dragleave在输入子元素时触发(并且似乎在对该元素进行任何更改时触发,包括显示/隐藏子元素)。

解决方案是检查是否pageXpageY等于0inside dragleave(但不是 drop)。

var $dropTarget = $("#container");
$(document).bind("dragenter", function(e) {
    if (e.target == this) {
         return;
    }
                
    $dropTarget.addClass("highlight");
    $dropTarget.find("[name='drop']").show();
    $dropTarget.find("[name='drag']").hide();
}).bind("dragleave", function(e) {
    if (e.originalEvent.pageX != 0 || e.originalEvent.pageY != 0) {
        return false;
    }
    
    // Could use .trigger("drop") here.
    $dropTarget.removeClass("highlight");
    $dropTarget.find("[name='drop']").hide();
    $dropTarget.find("[name='drag']").show();
}).bind("drop", function(e) {
    $dropTarget.removeClass("highlight");
    $dropTarget.find("[name='drop']").hide();
    $dropTarget.find("[name='drag']").show();
});​
于 2012-10-18T01:59:01.857 回答
1

我有一些使用拖放文件的项目,并且在我的项目中发现了相同的问题,这是您的问题的解决方案并在您的案例中进行了测试,这是 100% 的工作

这是神奇的代码:

<style type="text/css">
    .drag * {
        pointer-events: none;
    }
</style>

<div class="drag" id='container'>
<div name='drop' style='display: none;'>DROP HERE</div>
<div name='drag'>DRAG HERE</div>
</div> 
于 2020-10-14T06:15:44.897 回答
-1

我发现使用 Eric 的解决方案,如果我在使用此解决方案后将 Win10 Google Chrome 上的屏幕拖出(到另一个窗口),它对我不起作用。将条件更改为 AND 反而起作用了。

var $dropTarget = $("#container");
$(document).bind("dragenter", function(e) {
    if (e.target == this) {
         return;
    }

    $dropTarget.addClass("highlight");
    $dropTarget.find("[name='drop']").show();
    $dropTarget.find("[name='drag']").hide();
}).bind("dragleave", function(e) {
    if (e.originalEvent.pageX != 0 || e.originalEvent.pageY != 0) {
        return false;
    }

    // Could use .trigger("drop") here.
    $dropTarget.removeClass("highlight");
    $dropTarget.find("[name='drop']").hide();
    $dropTarget.find("[name='drag']").show();
}).bind("drop", function(e) {
    $dropTarget.removeClass("highlight");
    $dropTarget.find("[name='drop']").hide();
    $dropTarget.find("[name='drag']").show();
});​
于 2016-07-30T15:09:35.757 回答