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 仍在执行此操作。当您拖动文本节点时,它会触发两种dragenter
和dragleave
事件:一种是事件目标和relatedTarget 都是文本节点的父元素,另一种是目标是父元素和relatedTarget是实际的文本节点(甚至不是正确的 DOM 元素)。
解决方法是检查dragenter
和dragleave
处理程序中的这两种事件并忽略它们:
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 问题的非选定答案中找到了答案。我有一个<div>
,它有很多子元素。只要页面上有dragenter
,半透明覆盖<span>
就会在<div>
上可见。如您所见,“dragover”不像mouseover
。每当您将鼠标悬停在子元素上时,它都会触发 dragleave
。
解决方案? Dragout 它使dragover
工作起来更像mouseover
。很短。
【讨论】:
以上是关于Firefox 在文本上拖动时触发 dragleave的主要内容,如果未能解决你的问题,请参考以下文章