Firefox 在文本上拖动时触发 dragleave

Posted

技术标签:

【中文标题】Firefox 在文本上拖动时触发 dragleave【英文标题】:Firefox firing dragleave when dragging over text 【发布时间】:2012-12-21 02:04:20 【问题描述】:

我正在尝试跟踪整个屏幕的 dragenter/leave,这在 Chrome/Safari 中运行良好,这要归功于 https://***.com/a/10310815/698289 的 draghover 插件,如下所示:

$.fn.draghover = function(options) 
    return this.each(function() 

        var collection = $(),
            self = $(this);

        self.on('dragenter', function(e) 
            if (collection.size() === 0) 
                self.trigger('draghoverstart');
            
            collection = collection.add(e.target);
        );

        self.on('dragleave drop', function(e) 
            // timeout is needed because Firefox 3.6 fires the dragleave event on
            // the previous element before firing dragenter on the next one
            setTimeout( function() 
                collection = collection.not(e.target);
                if (collection.size() === 0) 
                    self.trigger('draghoverend');
                
            , 1);
        );
    );
;

function setText(text) 
    $('p.target').text(text);


$(document).ready(function() 
    $(window).draghover().on(
        'draghoverstart': function() 
            setText('enter');
        ,
        'draghoverend': function() 
            setText('leave');
        
    );
);

但是,当我拖动文本项时,Firefox 仍然给我带来问题,这里有一个小提琴来演示:http://jsfiddle.net/tusRy/6/

这是 Firefox 的错误还是可以用 JS 来驯服?还是有更稳健的方法来执行所有这些操作?

谢谢!

更新:将小提琴更新为 http://jsfiddle.net/tusRy/6/ 以减少混乱。解释小提琴的预期行为:

将文件拖到窗口中,p.target 应该是黄色的“ENTER”。 将文件拖出窗口,p.target 应该是红色的“LEAVE”。 在窗口中拖放一个文件,p.target 应该是红色的“LEAVE”。

在 Firefox 中,当您将文件拖到文本上时会触发 LEAVE 事件。

【问题讨论】:

根据jsfiddle.net/tusRy/7,我现在已经通过使用覆盖 div 来解决这个问题,但是我对这是解决方案并不满意,所以我会留下这个问题,直到有更好的想法来了。 【参考方案1】:

从 22.0 版开始,Firefox 仍在执行此操作。当您拖动文本节点时,它会触发两种dragenterdragleave 事件:一种是事件目标和relatedTarget 都是文本节点的父元素,另一种是目标是父元素和relatedTarget是实际的文本节点(甚至不是正确的 DOM 元素)。

解决方法是检查dragenterdragleave 处理程序中的这两种事件并忽略它们:

try 
    if(event.relatedTarget.nodeType == 3) return;
 catch(err) 
if(event.target === event.relatedTarget) return;

我使用 try/catch 块来检查 nodeType,因为偶尔会从文档外部(例如在其他 iframe 中)触发事件(莫名其妙地),并且尝试访问它们的 nodeType 会引发权限错误。

以下是实现: http://jsfiddle.net/9A7te/

【讨论】:

我相信 jQuery-2.1.1 对 dragenter 和 dragleave 的事件处理存在问题:我注意到,它没有将有问题的文本节点报告为 dragenter 和 dragleave 上的 event.target,而是而是传递文本节点的父元素。如果您仍然注意到问题,我想知道在这里本地化是否会有所帮助。 顺便说一句,这个答案对我帮助最大。如果我上面的答案不是很清楚:我的意思是在这个错误中,jQuery 本身不准确地将事件目标复制到它的自定义事件对象。我已经根据 event.originalEvent.target 和 event.originalEvent.relatedTarget 实施了 nodeType 检查,效果很好 完美运行!我将它添加到插件本身以避免在结束事件处理程序中重新编写它。在 Chrome 和 Firefox 中运行良好。尚未在其他浏览器中进行测试以验证任何愚蠢的错误,但这是我通常必须支持的仅有的两个主要浏览器。【参考方案2】:

1) 你的 dropzone 应该只有一个子元素,它可能包含你需要的一切。类似的东西

<div id="#dropzone">
    <div><!--Your contents here--></div>
</div>

2) 使用这个 CSS:

#dropzone *  pointer-events: none; 

您可能需要包含:before:after,因为* 不适用于它们。

这应该足以让 drop 在 Firefox 和 Chrome 中工作。在您的示例中,添加以下内容就足够了:

body *  pointer-events: none; 

在 CSS 的末尾。我已经在这里完成了:

http://jsfiddle.net/djsbellini/eKttq/

其他例子:

http://jsfiddle.net/djsbellini/6yZV6/1/ http://jsfiddle.net/djsbellini/yR8t8/

【讨论】:

【参考方案3】:

我想出了一种解决方案,但尚未在 Chrome 和 FF 以外的其他浏览器上进行测试,但到目前为止还有效。这就是setTimeout 现在的样子:

setTimeout( function() 
    var isChild = false;

    // in order to get permission errors, use the try-catch
    // to check if the relatedTarget is a child of the body
    try 
        isChild = $('body').find(e.relatedTarget).length ? true : isChild;
    
    catch(err) // do nothing

    collection = collection.not(e.target);
    if (collection.size() === 0 && !isChild) 
        self.trigger('draghoverend');
    
, 1);

这里的完整代码 - http://jsfiddle.net/tusRy/13/。

这个想法是检查相关标签是否是body的子标签,在这种情况下,我们仍然在浏览器中并且不应该触发draghoverend事件。由于这会在移出窗口时引发错误,因此我使用了 try 方法来避免它。

好吧,也许有更多 JS 技能的人可以改进这个:)

【讨论】:

【参考方案4】:

我在关于dragleave firing on child elements 的这个 SO 问题的非选定答案中找到了答案。我有一个&lt;div&gt;,它有很多子元素。只要页面上有dragenter,半透明覆盖&lt;span&gt; 就会在&lt;div&gt; 上可见。如您所见,“dragover”不像mouseover。每当您将鼠标悬停在子元素上时,它都会触发 dragleave

解决方案? Dragout 它使dragover 工作起来更像mouseover。很短。

【讨论】:

以上是关于Firefox 在文本上拖动时触发 dragleave的主要内容,如果未能解决你的问题,请参考以下文章

Firefox 在 div 滚动条上移动时触发拖动事件

在Firefox中拖动鼠标时如何防止文本选择?

在Firefox中拖动元素的问题

在窗口外拖动时如何检测Firefox中的dragleave事件

Chrome在拖动时将光标设置为文本,为啥?

H5的拖放事件(拖拽删除)