HTML5拖放行为

13

我正在广泛使用HTML5本地拖放功能,它几乎完全正常,只有一个小问题。

当页面上有任何东西被拖动时,我想要突出显示我的放置区域。最初我尝试通过在文档主体上放置jQuery监听器来实现这一点,代码如下:

$("body").live('dragover',function(event){lightdz(event)});
$("body").live('dragexit dragleave drop',function(event){dimdz(event)});

使用lightdz()和dimdz()修改页面上所有拖放区域的背景颜色样式属性,以使它们突出显示。但是这并没有起作用。每当拖动对象进入页面上的子元素(例如div容器)时,监听器都会将其标记为dragleave事件并降低拖放区的亮度。

我通过将监听器应用于页面上的所有可见元素而不仅仅是body来解决了这个问题。当它穿过一个元素到另一个元素的边界时,拖放区域偶尔会有轻微的可见闪烁,但看起来还不错。

无论如何,现在我已经改变了lightdz()和dimdz(),使它们对所有非拖放区域应用了一个快速的jQuery fadeTo()动画。当它工作时,看起来很棒,并且让用户非常清楚地知道他们可以和不能够在哪里投放东西。问题是当它通过元素边界时,它将应用淡入淡出动画。这比偶尔的背景颜色闪烁更加明显,特别是因为如果对象在多个边界上快速拖动,它将排队播放动画并使页面反复淡入淡出。

即使我不费心使用fadeTo()动画,只是改变透明度,它比背景颜色闪烁更加明显,因为整个页面发生变化而不仅仅是拖放区域元素。

有没有办法将整个页面作为单个元素参考拖放和离开事件?如果无法做到这一点,是否有任何办法检测发生在浏览器窗口外的丢弃操作?如果跳过dragleave事件,则看起来很好,但是如果将任何对象拖动到浏览器窗口之外然后将其放下,则整个页面都会变暗。

3个回答

13

我真的为这个问题的简单感到尴尬。

$("*:visible").live('dragenter dragover',function(event){lightdz(event)});

$("#page").live('dragleave dragexit',function(event)
{
    if(event.pageX == "0")
       dimdz(event);
});

$("*:visible").live('drop',function(event){dimdz(event)});

#page是一个全屏容器。如果dragleave事件将拖动的对象拖到浏览器窗口之外,event.pageX的值将为0。如果发生在其他地方,则其值将为非零。


1
似乎在某些浏览器上,它是event.originalEvent.pageX而不是event.pageX... - Nick Josevski

2
我可能过于复杂了,但我会像这样做:

我可能有点过于复杂了,但我会这样做:

var draggingFile = false;
var event2;

//elements with the class hotspots are OK
var hotspots = $(".hotspots");

//Handlers on the body for drag start & stop
$("body").live("dragover", function(event){ draggingFile = true; event2 = event; });
$("body").live("dragexit dragleave drop", function(event){ draggingFile = false; event2 = event; });

//Function checks to see if file is being dragged over an OK hotspot regardless of other elements infront
var isTargetOK = function(x, y){
    hotspots.each(function(i, el){
        el2 = $(el);
        var pos = el2.offset();
        if(x => pos.left && x <= pos.left+el2.width() && y => pos.top && y <= post.top+el2.height()){
            return true;
        }
    });
    return false;
};

//Mousemove handler on body
$("body").mousemove(function(e){
    //if user is dragging a file
    if(draggingFile){
        //Check to see if this is an OK element with mouse X & Y
        if(isOKTarget(e.pageX, e.pageY)){
            //Light em' up!
            lightdz(event2);
        } else { /* Fade em' :( */ dimdz(event2); }
    } else {
        dimdz(); //Having no parematers means just makes sure hotspots are off
    }
});

顺带一提,这可能不能直接起作用,所以你需要稍微调整一下以使其适用于你的代码。


我确实注意到fadeTo()存在一些错误。 从拖放相关事件的完全透明度到部分透明度的淡出似乎会立即发生,但反之则需要几秒钟的领先时间。 这在我的所有页面上都发生了,所以它可能只是我脚本的特异性,但我已决定直接更改不透明度作为纯CSS更改而不是动画。 看起来不太干净,但它可以工作,并且也使我的原始问题有些多余。 - R Hill
撤销那个说法。在Chrome中我仍然有问题。Firefox无缝处理CSS更改,但是Chrome在每次边界更改时闪烁。我会看看是否有类似这样的解决方案。 - R Hill

1

我尝试了这里的被接受的解决方案,但最终使用setTimeout来解决问题。如果浮动在顶部,页面宽容器会阻止下拉元素,并且如果它是下拉元素,仍然会导致问题,这让我非常困扰。

<body style="border: 1px solid black;">
    <div id="d0" style="border: 1px solid black;">&nbsp;</div>
    <div id="d1" style="border: 1px solid black; display: none; background-color: red;">-&gt; drop here &lt;-</div>
    <div id="d2" style="border: 1px solid black;">&nbsp;</div>
    <div style="float: left;">other element</div>
    <div style="float: left;">&nbsp;-&nbsp;</div>
    <div style="float: left;">another element</div>
    <br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/><br/>
</body>
<script type="text/javascript">
    var resetTimer;

    var f = function(e)
    {
        if (e.type == "dragover")
        {
            e.stopPropagation();
            e.preventDefault();
            if (resetTimer)
            {
                clearTimeout(resetTimer);
            }
            document.getElementById('d1').style.display = '';
        }
        else
        {
            var f = function()
            {
                document.getElementById('d1').style.display = 'none';
            };
            resetTimer = window.setTimeout(f, 25);  
        }
    };

    document.body.addEventListener("dragover", f, true);
    document.body.addEventListener("dragleave", f, true);
    document.getElementById('d1').addEventListener("drop", function(e){ f(); alert('dropped'); }, false);
</script>

如果你只是调用f();而不是window.setTimeout(f, 250);,你会看到元素显示和隐藏时出现一些令人讨厌的闪烁。

http://jsfiddle.net/guYWx/


闪烁的原因是当它进入放置区域时,在BODY上触发了dragleave事件,导致放置区域消失,再次触发dragover事件。我记得我解决了这个问题(我的项目是八九个月前的事情了,所以我记不清所有的细节),通过将dragover监听器应用于页面上所有可见的块级元素。你的解决方案可能更加优雅。 - R Hill
如果您将事件侦听器附加到文档(而不是正文),则如果文件被拖动到正文末尾以下,dragover事件也会触发。此解决方案不包括在当前页面上拖动元素,请参见此问题 - Bouke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接