firefox垃圾邮件ondragenter事件

时间:2015-11-17 23:40:45

标签: javascript html5 firefox

尝试构建一些拖放功能,并在Firefox中遇到一个奇怪的错误。我将整个文档的正文作为放置区域,并希望在页面上拖动某个对象时更改h1值。

似乎没有任何问题:http://jsfiddle.net/j7u6hLyj/

除了Firefox之外,它应该可以在任何地方使用。当我在页面中拖动对象时 - 除了在文本上拖动对象的情况之外没有问题,如果您尝试示例并将文件拖到文本上您会注意到ondragenter事件在对象浮动文本时不间断地被触发。它只发生在Firefox中。

2 个答案:

答案 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)。基本上任何破坏反馈循环的东西都可以。