尝试构建一些拖放功能,并在Firefox中遇到一个奇怪的错误。我将整个文档的正文作为放置区域,并希望在页面上拖动某个对象时更改h1
值。
似乎没有任何问题:http://jsfiddle.net/j7u6hLyj/
除了Firefox之外,它应该可以在任何地方使用。当我在页面中拖动对象时 - 除了在文本上拖动对象的情况之外没有问题,如果您尝试示例并将文件拖到文本上您会注意到ondragenter
事件在对象浮动文本时不间断地被触发。它只发生在Firefox中。
答案 0 :(得分:2)
似乎更改innerHTML正在重置事件是否已经被引发的状态,从而导致它陷入循环。这可能是Firefox中的一个错误。添加标记仅在以前未更改过时更改文本,可防止其卡在此循环中。然后,您可以处理dragleave事件以在需要时清除此标志。
var drop = document.getElementById('drop'),
text = document.getElementById('promo-text');
var textChanged = false;
drop.ondragenter = function () {
console.log('dragged!');
if (!textChanged) {
text.innerHTML = 'Drop it here!';
textChanged = true;
}
return false;
};
此代码在jsfiddle上运行:http://jsfiddle.net/17aq9dhs/
答案 1 :(得分:1)
问题的根本原因是您的代码正在设置反馈循环。至少在Firefox中。
当任何ondragenter
事件传播到您的body
元素时,您的代码会通过设置元素的innerHTML
属性来修改显示的文本。浏览器更新DOM中的元素,如果Firefox看到您在更新的元素上拖动某些内容并重新触发ondragenter
事件(然后将其传播回您的body
元素,重启整个过程。)
要解决这个问题,您只需从链中拉出一个链接即可打破反馈循环。例如,通过跟踪您是否已经更改了给定“拖动”事件的文本(基本上就像Adam Shaver建议的那样),或者通过检查文本是否已经显示“Drop it Here!”在分配给innerHTML
属性等之前。
如果你想让你的处理程序在多个“拖动”事件中工作(例如,每当用户将文本在“Drop file here here”和“Drop it here!”之间来回切换)时,请小心这种方法启动“拖动”操作,然后在不删除文件的情况下取消/结束它。如果您希望这样做,您必须在两端正确运行会计。
打破反馈循环的另一个选择是取消由文本元素触发的事件,使它们不会首先传播到body
。例如,像:
<h1 class="cover-heading" id="promo-text" ondragenter="cancelEvent(event);">Drop file somewhere here.</h1>
[...]
function cancelEvent(evt) {
if (! evt) {
evt = window.event;
}
if (evt) {
console.log("Canceling event");
evt.cancelBubble = true;
if (evt.stopImmediatePropagation) {
evt.stopImmediatePropagation();
}
}
return false;
}
http://jsfiddle.net/j7u6hLyj/2/
根据您当前的设置,这可能会更好,因为它不需要担心手动簿记。
其他方法也可能有效,例如检查事件的target
(或IE上的srcElement
)。基本上任何破坏反馈循环的东西都可以。